1 回答

TA貢獻1807條經(jīng)驗 獲得超9個贊
getData()對于具有異步 API 的數(shù)據(jù)存儲,您有一個相當經(jīng)典的競爭條件,如果您在數(shù)據(jù)處理中使用異步操作(在和之間),競爭條件會更糟setData()。異步操作允許另一個事件在中間運行你的處理,破壞了你的事件序列的原子性。
以下是如何將傳入的 tabId 放入隊列并確保您一次只處理其中一個事件的想法:
const queue = [];
chrome.tabs.onRemoved.addListener(async (newTabId) => {
queue.push(newTabId);
if (queue.length > 1) {
// already in the middle of processing one of these events
// just leave the id in the queue, it will get processed later
return;
}
async function run() {
// we will only ever have one of these "in-flight" at the same time
try {
let tabId = queue[0];
let data = await getData(); // async operation
... // modify data
await setData(data); // async operation
} finally {
queue.shift(); // remove this one from the queue
}
}
while (queue.length) {
try {
await run();
} catch(e) {
console.log(e);
// decide what to do if you get an error
}
}
});
這可以變得更通用,因此可以在多個地方(每個都有自己的隊列)重復使用,如下所示:
function enqueue(fn) {
const queue = [];
return async function(...args) {
queue.push(args); // add to end of queue
if (queue.length > 1) {
// already processing an item in the queue,
// leave this new one for later
return;
}
async function run() {
try {
const nextArgs = queue[0]; // get oldest item from the queue
await fn(...nextArgs); // process this queued item
} finally {
queue.shift(); // remove the one we just processed from the queue
}
}
// process all items in the queue
while (queue.length) {
try {
await run();
} catch(e) {
console.log(e);
// decide what to do if you get an error
}
}
}
}
chrome.tabs.onRemoved.addListener(enqueue(async function(tabId) {
let data = await getData(); // async operation
... // modify data
await setData(data); // async operation
}));
添加回答
舉報