javascript
jsp循环输出表格_「翻译」JS可视化学习之七:Promise、事件循环和异步2
喜歡排隊吧,它能保護你的時間和精力 - 排隊紀律維護員Event Loop
Promise和事件循環概覽圖
請注意上面這張圖,Promise和事件循環的那些事,將在這個圖上緩緩展開。
微任務和(宏)任務
好了,(經過上一節對Promise的理解)現在我們對如何創建Promise以及如何從Promise中獲取值多了一些了解。讓我們在script中添加更多的代碼,然后再次運行它:
等等,發生了什么?!
首先,輸出了"Start!"。好吧,顯而易見的:console.log('Start!') 就在第一行!但是,輸出的第二個值是"End!"而不是Promise的值!只有在"End!"輸出后,Promise的值才被輸出。這是怎么回事?
我們終于見識到Promise的真正力量!雖然JavaScript是單線程的,但是我們可以使用Promise添加異步行為!
但是稍等一下,我們以前不是見過了嗎?在JavaScript事件循環中(「翻譯」JavaScript的可視化學習之一:事件循環),我們不也可以使用瀏覽器的本地方法(如setTimeout)來創建某種異步行為嗎?
沒錯!但是,在事件循環中,實際上有兩種類型的隊列:(宏)任務隊列(或簡稱為任務隊列):(macro) task queue 和微任務隊列:microtask queue。(宏)任務隊列用于(宏)任務,微任務隊列用于微任務。
那么什么是(宏)任務,什么是微任務呢?下面表格羅列了一些最常用的!
(Macro)task:
setTimeout
setInterval
setImmediate
Microtask:
process.nextTick
Promise callback
queueMicrotask
啊,我們在微任務列表中看到了Promise!當Promise處理并調用其then()、catch()或finally()方法時,該方法內的回調將添加到微任務隊列中!這意味著then()、catch()或finally()方法中的回調不會立即執行,這實際上是在我們的JavaScript代碼中添加了一些異步行為!
那么then()、catch()或finally()回調函數在什么時候執行呢?事件循環為任務設定了不同的優先級:
1、當前在調用堆棧中的所有函數被執行,當它們返回一個值時,它們將從堆棧中彈出。
2、當調用堆棧為空時,所有排隊的微任務將一個接一個的彈出到調用堆棧中,并執行!(微任務本身也可以返回新的微任務,實際創建了一個無限的微任務循環)
3、如果調用堆棧和微任務隊列都為空,則事件循環將檢查(宏)任務隊列中是否還有任務。如果有,任務被彈出到調用堆棧,執行,然后彈出調用堆棧!
讓我們看一個簡單的例子,簡單地使用:
Task1: 一個立即添加到調用堆棧中的函數,例如在代碼中立即調用它。
Task2, Task3, Task4: 微任務,例如一個Promise的then回調,或使用queueMicrotask添加的任務。
Task5, Task6: (宏)任務,例如setTimeout或setImmediate回調。
首先,Task1返回一個值并從調用堆棧中彈出。然后,引擎檢查微任務隊列中排隊的任務。一旦所有任務都被放入調用堆棧并最終彈出,引擎將檢查(宏)任務隊列中的任務,任務將彈出到調用堆棧中,并在它們返回值時彈出。
好吧,好吧,粉色盒子夠多了。讓我們用一些真正的代碼來使用它!
console.log('Start!')setTimeout(() => {console.log('Timeout!')}, 0)Promise.resolve('Promise').then(res => console.log(res))console.log('End!')在這段代碼中,我們有宏任務setTimeout和微任務Promise的 then()回調。定位到setTimeout函數的行,讓我們一步一步地運行這段代碼,看看會輸出了什么!
小提示 - 在下面的示例中,我展示了如下方法console.log,setTimeout和Promise.resolve,他們被添加到調用堆棧中。它們是內部方法,實際上不會出現在堆棧跟蹤中 — 因此,如果您正在使用調試器并且在任何地方都看不到它們,請不要擔心!這么做只是為了讓解釋這個概念更容易,而不需要添加一堆示例代碼。
在第一行,引擎遇到console.log()方法。它被添加到調用堆棧中,然后輸出"Start!"到控制臺。方法從調用堆棧中彈出,引擎繼續運行。
引擎遇到setTimeout方法,該方法被彈出到調用堆棧中。setTimeout方法是瀏覽器的本地方法:它的回調函數(() => console.log('In timeout')) 將被添加到Web API中,直到計時器完成。雖然我們為計時器提供了值 0,但是回調仍然會首先被推送到Web API,之后它會被添加到(宏)任務隊列中:setTimeout是一個宏任務!
引擎遇到Promise.resolve()方法。這個Promise.resolve()方法被添加到調用堆棧中,之后處理并返回"Promise!"。然后它的then回調函數被添加到微任務隊列中。
引擎遇到console.log()方法。它會立即添加到調用堆棧中,然后輸出"End!"到控制臺,從調用堆棧中彈出,引擎繼續運行。
引擎發現調用堆?,F在是空的。由于調用堆棧是空的,它將檢查微任務隊列中是否有排隊的任務!是的,Promise的then回調正在等待!它被彈出到調用堆棧中,然后輸出Promise的值:在這里是字符串"promise!"。
引擎發現調用堆棧是空的,因此它將再次檢查微任務隊列,以查看是否有排隊的任務。不,微任務隊列都是空的。
是時候檢查(宏)任務隊列了:setTimeout回調仍在那里等待!setTimeout回調被彈出到調用堆棧。回調函數返回console.log方法,該方法輸出字符串“In timeout!”。setTimeout回調從調用堆棧中彈出。
終于,一切都完成了!現在看來我們之前看到的輸出結果并不是那么出乎意料。
翻譯來源:https://dev.to/lydiahallie/javascript-visualized-promises-async-await-5gke
總結
以上是生活随笔為你收集整理的jsp循环输出表格_「翻译」JS可视化学习之七:Promise、事件循环和异步2的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: linux的yum源怎么配(linux的
- 下一篇: 二类医疗器械资质备案代办(二类医疗器械资