在下面的代碼中,我使用 CSS DOM,這可能是計算量很大的。這顯然是訪問:after選擇器所必需的。renderItem方法將向 DOM 添加一個新專案(包括它在元素之后),這就是我使用該async函式的原因,await因為它在loadFromStorage.
但是,await似乎無法正常作業,或者renderItem函式內部發生了一些奇怪的事情。迭代器在n函式開始時正確更新(專案正確呈現到螢屏上,第console.debug一個以正確的順序列印正確的值),但在底部,第二個列印的值始終是最后一個迭代值(即在我的情況下是 4,因為我試圖從本地存盤中渲染 4 個專案)并且getCSSRule方法得到了錯誤的數字。
let books = []
let n = 0
const renderItem = async (entry, direction = 1) => {
const li = document.createElement('li')
const ul = document.querySelector('ul')
li.classList.add('item')
n = 1
console.debug(`iter: ${n}`)
li.id = (`item${n}`)
await addCSSRule(`#item${n}:after`)
li.innerText = entry.slice(0, entry.length - 13)
if (direction === 1)
ul.appendChild(li)
else
ul.insertBefore(li, ul.firstChild)
console.debug(`iter: ${n}`)
const s = await getCSSRule(`#item${n}::after`).catch(() => {
console.debug(`Failed to find ':after' selector of 'item${n}'`)
return false
})
s.style.content = "\"" entry.slice(entry.length - 13, entry.length) "\""
return true
}
const loadFromStorage = () => {
books = localStorage.getItem('books').split('//')
books.forEach(async (entry) => {
await renderItem(entry)
})
}
...
控制臺結果(考慮localStorage.getItem('books').split('//')回傳 4 項):
iter: 1
iter: 2
iter: 3
iter: 4
iter: 4 // Printed x4
我也一直在嘗試將此renderItem方法傳遞await給物件內部Promise,這給了我相同的結果。同樣,當我在n函式末尾更新迭代器時,也會發生同樣的事情,但在它的開頭。
如果我使用的某些術語在 JavaScript 的背景關系中不正確,我很抱歉,我已經很多年沒有使用這種語言了,目前我正在努力趕上。
uj5u.com熱心網友回復:
這里的關鍵問題是您將 async 函式傳遞給forEach,因此即使您在await它的主體內部,forEach也不會等待函式本身。為了說明這里的事件順序,假設您有 4 本書 A、B、C、D。您的執行將如下所示。
renderItem(A)n = 1(n 現在是 1)console.log(n)(日志 1)await addCSSRule(`#item${1}:after`)(這是一個真正的異步事件,因此這釋放了事件回圈以處理其他事情,即 中的下一個元素forEach)renderItem(B)n = 1(2)console.log(n)(日志 2)- ...
renderItem(C)...n = 1(3) ...await addCSSRulerenderItem(D)...n = 1(4) ...await addCSSRule
然后無論何時呼叫addCSSRule解決,無論您在哪個呼叫中。n4
解決方案
使用for await...of回圈而不是Array.prototype.forEach.
for await (const entry of books) {
await renderItem(entry);
}
或傳統的 for 回圈,并修改renderItem為n作為引數
for (let i = 0; i < books.length; i ) {
renderItem(books[i], i 1);
// we don't need to await in this case, and we add 1 to i so that the 'n' value is 1-indexed to match your current behaviour.
}
我更喜歡后一種選擇,因為它是避免可變全域狀態(您的n變數)的最佳實踐 - 因為它可能導致混亂的控制流和問題,就像您所擁有的一樣。
另一種選擇是將區域變數設定為n在內部遞增后的值renderItem,以便在該函式的持續時間內該值不會改變,但這對我來說似乎是一個非常棘手的解決方法。
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/462298.html
標籤:javascript 异步 异步等待
上一篇:從陣列回傳資料失敗
下一篇:任務延遲是否創建新執行緒?
