摘要:宏任務和微任務這兩個是指兩個隊列,腳本整體代碼的回調及渲染都會被加入到隊列中回調瀏覽器實現回調都會被加入到隊列。
1. macrotask (宏任務)和 microtask (微任務)
這兩個是指兩個隊列,腳本整體代碼、setTimeout、setInterval、setImmediate、I/O、的回調及UI渲染都會被加入到 macrotask 隊列中, process.nextTick回調、Promise(瀏覽器實現)、MutationObserver回調都會被加入到microtask隊列。
1 當瀏覽器進入事件循環時,先去看macrotask中有沒有具備執行條件的任務
2 如果有則選取一個(只選一個)執行
3 沒有則去看microtask隊列有沒有具備執行條件的任務
4 有則全部執行(全部執行)
5 去更新頁面
6 然后重復以上行為
2. Promise 介紹Promise主要的功能是將異步執行結果保存起來,從而使得我們不再用回調的方式去處理異步任務的結果,我們通過一個回調將異步任務的結果保存起來,在以后某個時刻通過各種姿勢去使用它new romise(excutor).then(function(result)}).then(function(result){});的方式去執行異步任務,Promise 是通過回調來實現的,但它將回調統一,使得我們不在去直接接觸回調,用看似有點像同步的方式去寫異步任務,也就僅僅是這樣而已,并沒有什么新東西,這種同步方式只能說是類似同步,下一篇會講寫法更接近同步、更加有建術的 generator 。
3. Promise 的構造函數應該是這樣的function Promise(excutor) { var self = this; var status = "PENDING"; //Promise的當前狀態 var data = undefined; //當前excutor(就是用戶的異步任務)的執行結果 self.onResolvedCallback = []; //excutor 執行成功后回調函數隊列 self.onRejectedCallback = []; //excutor 執行失敗后回調函數隊列 function resolve(value) { // TUDO 異步任務執行成功后的行為 // 1 改變當前promise的status值 調用該方法 PENDING->RESOLVED // 2 執行onResolvedCallback隊列里面的所有回調函數并傳遞異步任務的異步處理結果 // onResolvedCallback[i](data) } function reject(value) { // TUDO 異步任務執行失敗后的行為 // 1 改變當前promise的status值 調用該方法 PENDING->REJECTED // 2 執行onRejectedCallback隊列里面的所有回調函數并傳遞異步任務的異步處理結果 // onRejectedCallback[i](data) } excutor(resolve, reject); //執行用戶添加的任務 } Promise.prototype.then = function (onResolved, onRejected) { // onResolved異步任務執行成功的回調 // onRejected異步任務執行失敗后的回調 } 看起來就是這樣的 具體使用方式 new Promise(function(resolve,reject){ setTimeout(function(result){ // resolve(result) 或reject(result) 根據返回值決定 //這里我們確實還是寫了回調,但是我們在回調里面沒有做太多的事件 //僅僅是傳遞了異步處理結果 想想如果,我們在這里又要做依賴于result的 //異步任務會怎樣,回調地獄,代碼結構混亂,不容易讀 }); }).then(function(result){}) //這里的result是從上面的那個回調里面傳遞的,是同一個值4. 具體實現
(1) resolve 函數和 reject 函數
function Promise(excutor) { var self = this; var status = "PENDING"; //Promise的當前狀態 var data = undefined; //當前excutor(就是用戶的異步任務)的執行結果 self.onResolvedCallback = []; //excutor 執行成功后回調函數隊列 self.onRejectedCallback = []; //excutor 執行失敗后回調函數隊列 function resolve(value) { // TUDO 異步任務執行成功后的行為 if(self.status === "PENDING") { self.status = "REJECTED"; // 改變當前promise的status值 調用該方法 PENDING->RESOLVED self.data = value; // 更新當前的data for(var i in self.onResolvedCallback) { self.onResolvedCallback[i](self.data); //執行onResolvedCallback隊列里面的所有回調函數并傳遞異步任務的異步處理結果 } } } function reject(reson) { // TUDO 異步任務執行失敗后的行為 if(self.status === "PENDING") { self.status = "REJECTED"; self.data = reson; for(var i in self.onRejectedCallback) { self.onRejectedCallback[i](self.data); } } } try { excutor(resolve.bind(this), reject.bind(this)); //執行用戶添加的任務 /*這里為什么要通過通過 bind 來綁定上下文呢,主要是 resolve 依賴當 前 promise的內部屬性,在excutor函數體內,我們是通過 resolve(data) 或者reject(reson) 的方式來調用通過這種方式調用 在非嚴格模式 resolve或reject的上下文是windows,在嚴格模式下是undefined*/ } catch(e) { reject.bind(this)(e); //出現異常則通過reject向后傳遞 } }
(2) then 方法的實現
then方法應當具備如下功能
(1) then方法必須返回一個Promise對象,也就是,對應用戶添加的邏輯要進行包裝
(2) 同一個對象可多次調用then來添加邏輯,并且會按照添加順序執行
//例如: var promise = new Promise(function(resolve, reject) { //異步操作 并且在回調中調用了 resolve或者 reject將異步處理結果傳遞出去 }); promise.then(function(data){ //對異步結果data進行操作 }); promise.then(function(data){ //對異步結果data進行操作 }); //promise是同一個對象
(3) 可以鏈式調用
//例如: new Promise(function(resolve, reject){ //異步操作 并且在回調中調用了 resolve或者 reject將異步處理結果傳遞出去 }).then(function(data){}).then(function(data){});
這里第一次和第二次調用then的對象是兩個不同的對象,這里要注意
[1] 如果第一個then的參數也是一個Promise那么在第二個then的中會得到第一個then的處理結果 [2] 如果第一個then的參數是一個函數并且有返回值,則在第二個then中會接收到這個返回值 [3] 其它情況下都會得到通過 new Promise(fn) 這里這個異步fn的處理結果
(4) 我們寫的Promise 要和所有符合Promise規范的 Promise 能協同工作(例如瀏覽器自帶的、第三方庫的)
/** *@parms onResolved 任務成功時執行的回調 *@parms onRejected 任務失敗時執行的回調 */ Promise.prototype.then = function(onResolved, onRejected) { var self = this; var promiseThen; //then方法返回的promise //如果 onResolved或onRejected 不是函數我們忽略它,并且添加一個用于傳遞異步結果得函數 onResolved = typeof onResolved ==="function" ? onResolved : function(value) {resolve(value);} onRejected = typeof onRejected ==="function" ? onRejected : function(reson) {resolve(reson);} /*如果在調用then添加依賴于異步處理結果的時候,異步任務已經執行完了,那么 用異步的結果執行then里面添加的任務*/ if(self.status === "RESOLVED") { //這里要將then里面要添加的任務包裝成一個Promise,返回Promise 是為了(3)中的鏈式調用 return promiseThen = new Promise(function(resolve, reject) { try { //執行then添加的任務 var x = onResolved(self.data); if(x instanceof Promise) { /*如果then添加的任務有返回值,并且返回值是Promise對象 則讓promiseThen去接受x的狀態和data值注意,這里將 promiseThen的resolve,和reject作為x的then參數傳入,這 樣當promiseThen的resolve和reject會在適當的時候被調用 從而使得promiseThen接受了x的狀態和data值Promise的不 同對象之間能實現相互影響,是通過將自己的resolve和 reject添加到其它對象中*/ x.then(resolve, reject); } else resolve(x); //如果x不是Promise使用x的值作為promiseThen的結果 } catch (e) { reject(e); } }); } //和上面邏輯相同 if(self.status === "REJECTED") { return promiseThen = new Promise(function(resolve, reject){ try { var x = onRejected(self.data); if(x instanceof Promise){ x.then(resolve, reject); } }catch(e) { reject(e); } }); } if(self.status === "PENDING") { //當前Promise的異步任務沒有執行完,則將then里面的異步任務 包裝后放入隊列 //包裝方法和上面一樣,區別是上面立即執行,這里放入回調隊列。 return promiseThne = new Promise(function() { self.onResolvedCallback.push(function(){ try { var x = onResolved(self.data); if(x instanceof Promise) { x.then(resolve, reject); } catch(e) { reject(e); } } }); self.onRejectedCallback.push(function(){ try { var x = onRejected(self.data); if(x instanceof Promise) { x.then(resolve, reject); } catch(e) { reject(e); } } }); }); } }
寫到這里Promise具體實現的 (1)、(2)、(3)的功能已經完成了,也就是如果不考慮與其它
的Promise交互那么Promise的原理已經說清楚了,本來打算一篇文章寫完,但是篇幅太
長,所以打算分兩篇文章來寫,下一篇是generator,之后我會按照規范將(4)部分實現。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/83919.html
摘要:開始前的實現原理已經在規范解讀及實現細節一中說的很清楚了,這里將詳細分析規范中的解析過程,最后會實現一個并提供用于測試的代碼方法分析這里的調用會產生一個新的不同實例對于上一級的終值會作為的參數被傳入對于如果返回一個返回一個那么的狀態和值由決 開始前 Promise的實現原理已經在 Promise 規范解讀及實現細節 (一) 中說的很清楚了,這里將詳細分析 Promises/A+規范 中...
摘要:前兩個函數對應的兩種狀態和的回調函數。返回值是和對應的方法,但是會在下一事件循環返回。此外,在規范中,由方法生成的對象是已執行還是已拒絕,取決于由方法調用的那個回調是返回值還是拋出錯誤。但是對于其工作原理卻有些懵懂和好奇。 原文: https://blog.coding.net/blog/how-do-promises-work Javascript 采用回調函數(callback)來...
摘要:英文官方文檔原文前言寫本文的目的,是為了更好的理解,通過解讀翻譯原文,逐行解析原文通過代碼一行一行實現。英中原因是一個值結果表明被拒絕的原因。英中在法律允許的范圍內,組織已放棄所有版權及規范的相關或相鄰權利。 英文官方文檔原文:https://promisesaplus.com/ 前言 寫本文的目的,是為了更好的理解promise,通過解讀翻譯原文,逐行解析原文通過代碼一行一行實現。...
摘要:生成文件,是模塊構建的終點,包括輸出文件與輸出路徑。這里配置了處理各模塊的,包括預處理,編譯,圖片處理。各插件對象,在的事件流中執行對應的方法。修改改成引入模塊在目錄下執行, webpack原理解讀 本文抄自《深入淺出webpack》,建議想學習原理的手打一遍,操作一遍,給別人講一遍,然后就會了在閱讀前希望您已有webpack相關的實踐經驗,不然讀了也讀不懂 本文閱讀需要幾分鐘,理解需...
摘要:感謝大神的免費的計算機編程類中文書籍收錄并推薦地址,以后在倉庫里更新地址,聲音版全文狼叔如何正確的學習簡介現在,越來越多的科技公司和開發者開始使用開發各種應用。 說明 2017-12-14 我發了一篇文章《沒用過Node.js,就別瞎逼逼》是因為有人在知乎上黑Node.js。那篇文章的反響還是相當不錯的,甚至連著名的hax賀老都很認同,下班時讀那篇文章,竟然坐車的還坐過站了。大家可以很...
閱讀 2211·2019-08-30 15:54
閱讀 1947·2019-08-30 13:49
閱讀 666·2019-08-29 18:44
閱讀 824·2019-08-29 18:39
閱讀 1104·2019-08-29 15:40
閱讀 1524·2019-08-29 12:56
閱讀 3134·2019-08-26 11:39
閱讀 3094·2019-08-26 11:37