摘要:執行棧清空后,檢查微任務隊列,將可執行的微任務全部執行。對象的錯誤具有冒泡性質,會一直向后傳遞,直到被捕獲為止。返回的遍歷器對象,可以依次遍歷函數內部的每一個狀態。表示函數里有異步操作,表示緊跟在后面的表達式需要等待結果。
javascript 是單線程執行的,由js文件自上而下依次執行。即為同步執行,若是有網絡請求或者定時器等業務時,不能讓瀏覽器傻傻等待到結束后再繼續執行后面的js吧!所以js設計了異步模式!
下面是一個常見的定時器與promise的問題:
setTimeout(() => { console.log("我是第一個宏任務"); Promise.resolve().then(() => { console.log("我是第一個宏任務里的第一個微任務"); }); Promise.resolve().then(() => { console.log("我是第一個宏任務里的第二個微任務"); }); }, 0); setTimeout(() => { console.log("我是第二個宏任務"); }, 0); Promise.resolve().then(() => { console.log("我是第一個微任務"); }); console.log("執行同步任務");
執行結果如下:
為什么是這種執行結果?
這就要說到js的執行機制:事件循環(event loop)!
當JS解析執行時,會被引擎分為兩類任務,同步任務(synchronous) 和 異步任務(asynchronous)。
對于同步任務來說,會被推到執行棧按順序去執行這些任務。
對于異步任務來說,當其可以被執行時,會被放到一個 任務隊列(task queue) 里等待JS引擎去執行。
當執行棧中的所有同步任務完成后,JS引擎才會去任務隊列里查看是否有任務存在,并將任務放到執行棧中去執行,執行完了又會去任務隊列里查看是否有已經可以執行的任務。這種循環檢查的機制,就叫做事件循環(Event Loop)。
對于任務隊列,其實是有更細的分類。其被分為 微任務(microtask)隊列 & 宏任務(macrotask)隊列
宏任務: setTimeout、setInterval等,會被放在宏任務(macrotask)隊列。
微任務: Promise的then、Mutation Observer等,會被放在微任務(microtask)隊列。
1.首先執行執行棧里的任務。
2.執行棧清空后,檢查微任務(microtask)隊列,將可執行的微任務全部執行。
3.取宏任務(macrotask)隊列中的第一項執行。
4.回到第二步。
現在我們知道了為什么定時器會晚于promise執行了。下面我們討論一下微任務的幾種實現情況:Promsie、Generator、async/await。
===Promsie===
Promise對象是一個構造函數,用來生成Promise實例;
const promise = new Promise(function(resolve, reject) { // ... some code if (/* 異步操作成功 */){ resolve(value); } else { reject(error); } });
Promise 新建后就會立即執行。
let promise = new Promise(function(resolve, reject) { console.log("Promise"); resolve(); }); promise.then(function() { console.log("resolved."); }); console.log("Hi!"); // Promise // Hi! // resolved
Promise 對象的錯誤具有“冒泡”性質,會一直向后傳遞,直到被捕獲為止。也就是說,錯誤總是會被下一個catch語句捕獲。
// bad promise .then(function(data) { // success }, function(err) { // error }); // good promise .then(function(data) { //cb // success }) .catch(function(err) { // error });
跟傳統的try/catch代碼塊不同的是,如果沒有使用catch方法指定錯誤處理的回調函數,Promise 對象拋出的錯誤不會傳遞到外層代碼,即不會有任何反應。
===Generator===
Generator 函數是一個狀態機,封裝了多個內部狀態。
執行 Generator 函數會返回一個遍歷器對象,也就是說,Generator 函數除了狀態機,還是一個遍歷器對象生成函數。返回的遍歷器對象,可以依次遍歷 Generator 函數內部的每一個狀態。
function* helloWorldGenerator() { yield "hello"; yield "world"; return "ending"; } var hw = helloWorldGenerator();
===async===
async 函數是什么?一句話,它就是 Generator 函數的語法糖。
(1)內置執行器。
Generator 函數的執行必須靠執行器,所以才有了co模塊,而async函數自帶執行器。也就是說,async函數的執行,與普通函數一模一樣,只要一行。
asyncReadFile();
上面的代碼調用了asyncReadFile函數,然后它就會自動執行,輸出最后結果。這完全不像 Generator 函數,需要調用next方法,或者用co模塊,才能真正執行,得到最后結果。
(2)更好的語義。
async和await,比起星號和yield,語義更清楚了。async表示函數里有異步操作,await表示緊跟在后面的表達式需要等待結果。
(3)更廣的適用性。
co模塊約定,yield命令后面只能是 Thunk 函數或 Promise 對象,而async函數的await命令后面,可以是 Promise 對象和原始類型的值(數值、字符串和布爾值,但這時會自動轉成立即 resolved 的 Promise 對象)。
(4)返回值是 Promise。
async函數的返回值是 Promise 對象,這比 Generator 函數的返回值是 Iterator 對象方便多了。你可以用then方法指定下一步的操作。
進一步說,async函數完全可以看作多個異步操作,包裝成的一個 Promise 對象,而await命令就是內部then命令的語法糖。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/105427.html
摘要:的翻譯文檔由的維護很多人說,阮老師已經有一本關于的書了入門,覺得看看這本書就足夠了。前端的異步解決方案之和異步編程模式在前端開發過程中,顯得越來越重要。為了讓編程更美好,我們就需要引入來降低異步編程的復雜性。 JavaScript Promise 迷你書(中文版) 超詳細介紹promise的gitbook,看完再不會promise...... 本書的目的是以目前還在制定中的ECMASc...
摘要:接下來,我們一起來看看中的異步編程,具體有哪幾種。實現異步編程的方法一回調函數上面不止一次提到了回調函數。它是異步編程中,最基本的方法。四對象接下來,我們聊聊與相關的異步編程方法,對象。 showImg(https://segmentfault.com/img/bVbneWy?w=1600&h=1200); 前言 最近,小伙伴S 問了我一段代碼: const funB = (value...
摘要:從最開始的到封裝后的都在試圖解決異步編程過程中的問題。為了讓編程更美好,我們就需要引入來降低異步編程的復雜性。寫一個符合規范并可配合使用的寫一個符合規范并可配合使用的理解的工作原理采用回調函數來處理異步編程。 JavaScript怎么使用循環代替(異步)遞歸 問題描述 在開發過程中,遇到一個需求:在系統初始化時通過http獲取一個第三方服務器端的列表,第三方服務器提供了一個接口,可通過...
摘要:回調函數,一般在同步情境下是最后執行的,而在異步情境下有可能不執行,因為事件沒有被觸發或者條件不滿足。同步方式請求異步同步請求當請求開始發送時,瀏覽器事件線程通知主線程,讓線程發送數據請求,主線程收到 一直以來都知道JavaScript是一門單線程語言,在筆試過程中不斷的遇到一些輸出結果的問題,考量的是對異步編程掌握情況。一般被問到異步的時候腦子里第一反應就是Ajax,setTimse...
摘要:異步編程解決方案筆記最近讀了樸靈老師的深入淺出中異步編程一章,并參考了一些有趣的文章。另外回調函數中的也失去了意義,這會使我們的程序必須依賴于副作用。 JavaScript 異步編程解決方案筆記 最近讀了樸靈老師的《深入淺出NodeJS》中《異步編程》一章,并參考了一些有趣的文章。在此做個筆記,記錄并鞏固學到的知識。 JavaScript異步編程的兩個核心難點 異步I/O、事件驅動使得...
摘要:調用棧被清空,消息隊列中并無任務,線程停止,事件循環結束。不確定的時間點請求返回,將設定好的回調函數放入消息隊列。調用棧執行完畢執行消息隊列任務。請求并發回調函數執行順序無法確定。 異步編程 JavaScript中異步編程問題可以說是基礎中的重點,也是比較難理解的地方。首先要弄懂的是什么叫異步? 我們的代碼在執行的時候是從上到下按順序執行,一段代碼執行了之后才會執行下一段代碼,這種方式...
閱讀 2054·2021-09-07 10:14
閱讀 1486·2019-08-30 15:53
閱讀 2277·2019-08-30 12:43
閱讀 2868·2019-08-29 16:37
閱讀 762·2019-08-26 13:29
閱讀 2005·2019-08-26 13:28
閱讀 448·2019-08-23 18:33
閱讀 3526·2019-08-23 16:09