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