使用IndexedDB作为浏览器内缓存。我做对了吗?

时间:2019-03-21 00:46:48

标签: javascript indexeddb dexie

在我的网站上:

  • 用户有很多活动
  • 每个活动都具有encode_polyline数据
  • 我在地图上显示这些encode_polyline

我想使用IndexedDB(通过Dexie)作为浏览器内缓存,这样他们每次查看地图时都不需要重新下载完整的Activity集。我以前从未使用过IndexedDB,所以我不知道自己是在做傻事还是在忽略任何边缘情况。


以下是我认为总体过程的概括描述:

  • 找出服务器上存在的内容
  • 删除IndexedDB中存在但服务器上不存在的所有内容
  • 找出IndexedDB中存在的内容
  • 仅请求IndexedDB中缺少的数据
  • 将新数据存储在IndexedDB中
  • 从IndexedDB中查询所有数据

在所有这些方面,我们需要专注于该用户。一个人可能查看许多人的页面,因此在IndexedDB中拥有许多人的数据的副本。因此,对服务器和IndexedDB的查询需要知道所引用的用户ID。


这是我决定做的英语版本:

  • 从服务器收集所有此用户的活动ID
  • 删除IndexedDB中不应该存在的任何内容(从可能仍存在于IndexedDB的站点中删除的东西)
  • 从IndexedDB收集所有此用户的活动ID
  • 过滤掉IndexedDB和服务器中存在的所有内容
  • 如果没有新的encoded_polylines要检索,则putItemsFromIndexeddbOnMap(如下所述)
  • 如果要检索新的encode_polyline:从服务器检索那些,然后将它们存储在IndexedDB中,然后将putItemsFromIndexeddbOnMap

对于putItemsFromIndexeddbOnMap:

  • 从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'
  });
}

...我做对了吗?

0 个答案:

没有答案