Javascript 从另一个选项卡获取IndexedDB更新上的事件

Javascript 从另一个选项卡获取IndexedDB更新上的事件,javascript,events,indexeddb,Javascript,Events,Indexeddb,如果我在多个选项卡中打开了IndexedDB数据库,我是否可以在不重新加载的情况下跟踪所有选项卡上的数据更改?单独使用IndexedDB无法实现这一点。您基本上有两种选择: 以一定频率轮询IndexedDB并检查新值 使用其他交叉表通信方式发送一个信号,需要检查IndexedDB中的新值。例如,localStorage(当某些内容发生更改时会发出交叉选项卡事件)或BroadcastChannel(专为交叉选项卡通信而设计,但没有完善的跨浏览器支持) 为了扩展dumbmatter的回答,下面是我如

如果我在多个选项卡中打开了
IndexedDB
数据库,我是否可以在不重新加载的情况下跟踪所有选项卡上的数据更改?

单独使用IndexedDB无法实现这一点。您基本上有两种选择:

  • 以一定频率轮询IndexedDB并检查新值

  • 使用其他交叉表通信方式发送一个信号,需要检查IndexedDB中的新值。例如,localStorage(当某些内容发生更改时会发出交叉选项卡事件)或BroadcastChannel(专为交叉选项卡通信而设计,但没有完善的跨浏览器支持)


  • 为了扩展dumbmatter的回答,下面是我如何使用BroadcastChannel实现它的。如果你想获得更多的支持,我建议使用广播频道而不是广播频道

    function putThing(db, channel, thing) {
      return new Promise(function(resolve, reject) {
        const transaction = db.transaction('things', 'readwrite');
        transaction.oncomplete = function(event) {
          const message = {operation: 'updated', id: thing.id};
          channel.postMessage(message);
          resolve();
        };
        transaction.onerror = function(event) {
          reject(event.target.error);
        };
    
        const store = transaction.objectStore('things');
        store.put(thing);
      });
    }
    
    // In tab where operation occurs
    const db = await open(...);
    const channel = new BroadcastChannel('myChannel');
    await putThing(db, channel, thing);
    channel.close();
    db.close();
    
    // In other tab where you want observation of changes
    const channel = new BroadcastChannel('myChannel');
    channel.onmessage = function(event) {
      const message = event.data;
      console.log('A message occurred', message);
    };
    
    
    有几点:

    • 频道不能向自身广播,所以它自己的消息侦听器函数上的同一个选项卡将无法获取它的消息。但是,您可以在同一选项卡上创建具有相同通道名称的多个通道实例,如果您需要该功能,每个实例都将获得其他实例的消息
    • 通道应该是短期的,因此在完成后关闭通道。但是,这也可能是一种情况,即您希望频道在页面打开时保持打开状态
    • 通道消息遵循与在数据库中存储对象类似的限制,例如,您只能传递简单属性值之类的数据,而不能传递函数或自定义对象实例

    选项卡之间的通信无法通过IndexedDB实现?我不熟悉IndexedDB。它可能有某种作用。当我们不知道targetWindow时,我们如何使用postMessage?@Srikan使用广播频道而不是postMessage可以很容易地解决这个问题,因为广播频道会将其发送到所有窗口,而任何窗口都可以响应。