我試圖避免異步函式的并發性,以便等待該函式的第一次呼叫完成,然后我才能再次呼叫相同的函式:
const disallowConcurrency = (fn) => {
let inprogressPromise = Promise.resolve();
return async(...args) => {
await inprogressPromise;
inprogressPromise = inprogressPromise.then(() => fn(...args));
};
};
const initCmp = async(arg) => {
return new Promise((res) => {
console.log('executed');
setTimeout(() => res(console.log(arg)), 1000);
});
};
const cmpConcurrentFunction = disallowConcurrency(initCmp);
cmpConcurrentFunction('I am called 1 second later');
cmpConcurrentFunction('I am called 2 seconds later');
所以在這里我創建了一個帶有承諾的閉包作為傳遞給內部函式的值。return 函式將等待上一次呼叫(在第一次運行時它是一個已解決的 Promise ),并將分配給inprogressPromise由回傳的thenPromise,在這種情況下,它將是該initCmp函式回傳的一個新 Promise。所以下次我們呼叫該函式時,它將等待前一個函式完成。至少我是這樣理解的。我做對了嗎?
但是我不明白為什么如果我洗掉這樣await inprogressPromise的例子,它為什么會繼續作業:
const disallowConcurrency = (fn) => {
let inprogressPromise = Promise.resolve();
return async (...args) => {
inprogressPromise = inprogressPromise.then(() => fn(...args));
};
};
所以await沒有必要嗎?為什么?
此外,我希望這能奏效:
const disallowConcurrency = (fn) => {
let inprogressPromise = Promise.resolve();
return async (...args) => {
await inprogressPromise;
inprogressPromise = fn(...args);
};
};
因為我在想,首先我在等待之前的承諾完成,然后我會呼叫并將回傳的承諾分配給inprogressPromise.
但它不起作用,兩個函式同時被呼叫。
有人可以澄清一下這里發生了什么嗎?
如果您嘗試代碼,您將看到第二次呼叫
cmpConcurrentFunction("I am called 2 seconds later")
將等待第一個承諾完成。
基本上我已經撰寫了一個節點包,它通過 npm 匯入到 Web 應用程式的瀏覽器中。這個節點包庫有一個 init 函式,它有一些異步代碼,可以在代碼的不同部分多次呼叫。例如,如果第二次呼叫,我想確保在嘗試再次執行代碼之前完成第一次執行。
但我的意思是試圖理解為什么該代碼有效,以及如果我使用最后一個版本為什么它不起作用
謝謝!
uj5u.com熱心網友回復:
為了回答您的問題,讓我首先嘗試解釋您的代碼是如何作業的。
了解您的代碼是如何作業的
以下步驟解釋了代碼的執行:
腳本執行開始
呼叫
disallowConcurrency函式,initCmp作為引數傳入。cmpConcurrentFunction被賦予disallowConcurrency函式的回傳值cmpConcurrentFunction第一次呼叫,'I am called 1 second later'作為引數傳入。在此呼叫期間,inprogressPromise是由Promise.resolve(). 等待它會暫停函式執行。第二次呼叫
cmpConcurrentFunction,'I am called 2 seconds later'作為引數傳入。在第二次呼叫期間,inprogressPromise仍然是由Promise.resolve(). 等待它會暫停函式執行。腳本的同步執行到此結束。事件回圈現在可以開始處理微任務佇列
由于第一次呼叫 的結果而暫停的函式
cmpConcurrentFunction被恢復,then()在回傳的承諾上呼叫方法Promise.resolve()。的值inprogressPromise通過為其分配一個由回傳的新承諾來更新inprogressPromise.then(...)由于第二次呼叫而暫停的函式
cmpConcurrentFunction被恢復。從第 6 步開始,我們知道這inprogressPromise是一個由inprogressPromise.then(...). 因此,呼叫then()它,我們只是創建了一個 Promise 鏈,then()在步驟 6 中創建的 Promise 鏈的末尾添加一個新的方法呼叫。此時,我們有一個如下所示的鏈:
inProgressPromise .then(() => fn('I am called 1 second later')) .then(() => fn('I am called 2 seconds later'))呼叫第一個方法的回呼函式,
then然后呼叫fn引數,也就是initCmp函式。呼叫initCmp會設定一個計時器,該計時器會initCmp在 1 秒后解決承諾回傳。當承諾在 1 秒后解決時,'I am called 1 second later'將登錄到控制臺。當第一個方法
initComp的回呼函式中第一次呼叫函式then回傳的promise被決議時,它決議第一個then方法回傳的promise。這導致呼叫第二種then方法的回呼函式。這再次呼叫該initComp函式,然后回傳一個新的 Promise,該 Promise 在另外 1 秒后被決議。
這解釋了為什么您會'I am called 2 seconds later'在 2 秒后看到登錄控制臺。
現在回答你的問題:
但我不明白為什么如果我洗掉 await inprogressPromise 這會繼續作業
await inprogressPromise除了暫停對cmpConcurrentFunction函式的呼叫之外,在您的代碼中沒有任何用途。兩個呼叫都等待由 . 回傳的相同承諾Promise.resolve()。
所以等待是沒有必要的?為什么?
因為您在控制臺上看到的輸出不是因為await,而是因為兩次呼叫該cmpConcurrentFunction函式而構建的承諾鏈(上面的第 7 步)。
此外,我希望這能奏效:
const disallowConcurrency = (fn) => { let inprogressPromise = Promise.resolve(); return async (...args) => { await inprogressPromise; inprogressPromise = fn(...args); }; };
上面的代碼不能作為您的原始代碼作業,因為現在未構造承諾鏈,這是原始代碼產生的輸出的關鍵。
使用 的這種實作disallowConcurrency,您的代碼將按如下所述執行:
呼叫
cmpConcurrentFunction函式,'I am called 1 second later'作為引數傳入等待
inprogressPromise暫停函式執行第二次呼叫
cmpConcurrentFunction,'I am called 2 seconds later'作為引數傳入等待
inprogressPromise暫停函式執行。此時, 的兩個呼叫cmpConcurrentFunction都被暫停,并且兩個函式呼叫都在等待由于呼叫而創建的同一個PromisePromise.resolve()。這是這里的關鍵點:函式的兩個呼叫都
cmpConcurrentFunction在等待由. 為什么兩個呼叫都在等待同一個承諾?因為在第一次呼叫 of被恢復并呼叫函式之前第二次呼叫了Promise.resolve()cmpConcurrentFunctioncmpConcurrentFunctioninitComp恢復第一次呼叫
cmpConcurrentFunction,呼叫initComp函式并將其回傳值分配給inprogressPromise。呼叫
initComp函式設定一個計時器,該計時器決議承諾initComp函式在 1 秒后回傳繼續第二次呼叫
cmpConcurrentFunction,呼叫initComp函式并將其回傳值分配給,覆寫第一次呼叫函式回傳的 promiseinprogressPromise的當前值。inprogressPromiseinitComp呼叫
initComp函式設定一個計時器,該計時器決議承諾initComp函式在 1 秒后回傳
此時,initComp函式已被呼叫兩次,設定了兩個單獨的計時器,每個計時器在 1 秒后解決它們各自的承諾。
總結一下函式的原始實作disallowConcurrency和這個函式之間的區別是,在原始實作中,你有一個按順序決議承諾的承諾鏈,而在第二個實施中,你有兩個獨立的承諾(不依賴于彼此) 并且它們在每個 1 秒后解決。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/469326.html
標籤:javascript 异步 异步等待 承诺 es6-承诺
