我有一个工作器,它在页面打开时启动。工作器打开一个事务,检查记录上是否存在一个值,如果没有,则需要进行一个获取调用来获取该值。
我的问题是,我在读/写事务中这样做,但提取是异步的,在返回提取之前提交事务。如果我可以保证只有一个页面同时访问逻辑,那么我就可以在没有事务的情况下这样做,例如获取数据,检查它,如果需要,获取值和更新。但我不能保证一个页面。
所以问题是我如何保证第二页不会在第一页启动了获取新值的过程之后,再启动这个过程呢?
async function start(message) {
var result = await new Promise(async (resolve, reject) => {
let transaction = db.transaction(["Client"], "readwrite")
let objectStore = transaction.objectStore("Client");
let request = objectStore.get(message.client_name);
request.onerror = (event) => {
reject(event);
};
request.onsuccess = async () => {
try {
let data = request.result
if (!data) {
data = {
client_name: message.client_name,
sequence: 0,
api_base_url: message.api_base_url || 'https://api.local'
}
}
if (!data.last_access || dateDiff(Date.parse(data.last_access), new Date(), "m") > 20) {
let response = await fetch(data.api_base_url + '/v1/hello');
let responseData = await response.json();
data.id = responseData.id;
data.last_access = responseData.dt;
}
objectStore.put(data); // <-- Here is where it errors
resolve(data.sequence);
} catch (error) {
reject(error);
}
}
});
return result;
}
2条答案
按热度按时间wlwcrazw1#
目前还没有很好的方法来做到这一点。
如果你使用的是Dexie,它有a
waitFor
function,它可以让你在等待另一个承诺解决的同时保持一个事务打开。请谨慎使用,因为它可能会给浏览器带来不必要的CPU负载。在执行给定的承诺时,一个单独的任务将通过在事务处理上传播伪请求来保持事务处理处于活动状态。
如果你不使用Dexie,你可以自己实现同样的事情。在检查你的获取承诺是否已经解决的同时,继续发出请求。
最好是找到某种方法,在获取过程中不必保持事务活动。比如在localStorage中存储一个标志,以防止第二个调用执行任何操作?或者如果第二个调用在第一个调用完成之前开始,则取消第一个获取?我不确定您到底想做什么,但通常有一些方法可以解决IndexedDB的这种限制。
c9x0cxw02#
一种方法是使用SharedWorker来执行该操作。
这样,所有页面示例(及其Dedicated Workers)都将使用同一个SharedWorker,它将能够跟踪事务状态,从而能够确定是否应该发出新的请求。
虽然Safari不支持它,但我想这总比没有好。