На моем сайте:
- У пользователей есть много действий
- Каждое действие имеет данные encoded_polyline
- Я отображаю эти encoded_polylines на карте
Я хочу использовать IndexedDB (через Dexie ) в качестве кеша в браузере, чтобы им не нужно было повторно загружать свой полный набор действий каждый раз, когда они просматривают свою карту.Я никогда не использовал IndexedDB раньше, поэтому я не знаю, делаю ли я что-нибудь глупое или пропускаю какие-либо крайние случаи.
Вот высокоуровневое описание всего процесса:
- Выясните, что существует на сервере
- Удалите все, что присутствует в IndexedDB, но отсутствует на сервере
- Выясните, что существует в IndexedDB
- Запрос только данных, отсутствующих в IndexedDB
- Сохранение новых данных в IndexedDB
- Запрос всех данных из IndexedDB
На протяжении всехэто, нам нужно сосредоточиться на этом пользователе .Человек может просматривать страницы многих людей и, следовательно, иметь копию данных многих людей в IndexedDB.Таким образом, запросы к серверу и IndexedDB должны знать, на какой идентификатор пользователя ссылаются.
Вот версия того, что я решил сделать на английском языке:
- Соберите все идентификаторы активности этого пользователя с сервера
- Удалите все в IndexedDB, чего там быть не должно (вещи, удаленные с сайта, которые все еще могут существовать в IndexedDB)
- Соберите все данные этого пользователяИдентификаторы активности из IndexedDB
- Отфильтруйте все, что присутствует в IndexedDB и на сервере
- Если нет новых encoded_polylines для извлечения, тогда
putItemsFromIndexeddbOnMap
(описано ниже) - Если естьявляются новыми codeded_polylines для извлечения: получить их с сервера, затем сохранить их в IndexedDB, затем
putItemsFromIndexeddbOnMap
Для putItemsFromIndexeddbOnMap:
- Получить все encoded_polylines этого пользователя изIndexedDB
- Вставить эти данные в массив
- Показать этот массив данных на карте
Воткод JavaScript, который делает то, что я объяснил выше (с некоторым ERB, потому что этот JavaScript встроен в представление Rails):
var db = new Dexie("db_name");
db.version(1).stores({ activities: "id,user_id" });
db.open();
// get this user's activity IDs from the server
fetch('/users/' + <%= @user.id %> + '/activity_ids.json', { credentials: 'same-origin' }
).then(response => { return response.json() }
).then(activityIdsJson => {
// remove items from IndexedDB for this user that are not in activityIdsJson
// this keeps data that was deleted in the site from sticking around in IndexedDB
db.activities
.where('id')
.noneOf(activityIdsJson)
.and(function(item) { return item.user_id === <%= @user.id %> })
.keys()
.then(removeActivityIds => {
db.activities.bulkDelete(removeActivityIds);
});
// get this user's existing activity IDs out of IndexedDB
db.activities.where({user_id: <%= @user.id %>}).primaryKeys(function(primaryKeys) {
// filter out the activity IDs that are already in IndexedDB
var neededIds = activityIdsJson.filter((id) => !primaryKeys.includes(id));
if(Array.isArray(neededIds) && neededIds.length === 0) {
// we do not need to request any new data so query IndexedDB directly
putItemsFromIndexeddbOnMap();
} else if(Array.isArray(neededIds)) {
if(neededIds.equals(activityIdsJson)) {
// we need all data so do not pass the `only` param
neededIds = [];
}
// get new data (encoded_polylines for display on the map)
fetch('/users/' + <%= @user.id %> + '/encoded_polylines.json?only=' + neededIds, { credentials: 'same-origin' }
).then(response => { return response.json() }
).then(newEncodedPolylinesJson => {
// store the new encoded_polylines in IndexedDB
db.activities.bulkPut(newEncodedPolylinesJson).then(_unused => {
// pull all encoded_polylines out of IndexedDB
putItemsFromIndexeddbOnMap();
});
});
}
});
});
function putItemsFromIndexeddbOnMap() {
var featureCollection = [];
db.activities.where({user_id: <%= @user.id %>}).each(activity => {
featureCollection.push({
type: 'Feature',
geometry: polyline.toGeoJSON(activity['encoded_polyline'])
});
}).then(function() {
// if there are any polylines, add them to the map
if(featureCollection.length > 0) {
if(map.isStyleLoaded()) {
// map has fully loaded so add polylines to the map
addPolylineLayer(featureCollection);
} else {
// map is still loading, so wait for that to complete
map.on('style.load', addPolylineLayer(featureCollection));
}
}
}).catch(error => {
console.error(error.stack || error);
});
}
function addPolylineLayer(data) {
map.addSource('polylineCollection', {
type: 'geojson',
data: {
type: 'FeatureCollection',
features: data
}
});
map.addLayer({
id: 'polylineCollection',
type: 'line',
source: 'polylineCollection'
});
}
... Правильно ли я делаю?