重點寫在開頭吧。
promise 簡單用法
new Promise ((res, rej) => {執(zhí)行函數(shù); res(data)}).then(data => 處理(data))
傳統(tǒng)觀念上拆分
1. new Promise -> 實例化過程 2.(res, rej) => {執(zhí)行函數(shù); res(data)} -> 執(zhí)行函數(shù)并拋出數(shù)據(jù) 3.then(data => process(data)) -> 處理拋出值
但是 實際上 then 主要是用來 聲明回調(diào)函數(shù),回調(diào)函數(shù)的執(zhí)行一般都是在實例化的時候
(因為實例化傳入的函數(shù)很多都是異步,執(zhí)行慢;這有點類似于觀察者模式,在subscribe中去聲明回調(diào),真正的執(zhí)行實際上在next的時候)
所以:
一般實際執(zhí)行順序拆分(按照執(zhí)行速度拆分排序)
1.new Promise -> 實例化過程 2.then(data => process(data)) -> 聲明回調(diào)函數(shù) 3.(res, rej) => {執(zhí)行函數(shù); res(data)} -> 用then 中聲明的回調(diào)函數(shù) 處理 這個res拋出的data
但是還有一種情況,就是實例化時候的執(zhí)行函數(shù)處理速度超過了then的聲明(按照執(zhí)行速度拆分排序)
1. new Promise -> 實例化過程 2.(res, rej) => {執(zhí)行函數(shù); res(data)} -> 執(zhí)行函數(shù)并拋出數(shù)據(jù),并且then尚未聲明完成 3.then(data => process(data)) -> 直接執(zhí)行函數(shù)
簡單點說,就是實例化時候,傳入的函數(shù),和 then 聲明,到底誰先完成這是promise唯一的難點。
這么說,如果“執(zhí)行函數(shù)“ 執(zhí)行完成,執(zhí)行res(data)時,then還沒聲明完,那么回調(diào)函數(shù)就會為空,這個時候就得讓then 中 回調(diào)函數(shù)在聲明完成的之后直接執(zhí)行
亦或者 ,then 聲明完成時候,還沒有res(data), 那么就得讓then 中聲明的方法先加入到一個隊列,等待res(data)時候依次執(zhí)行;
如果這邊沒有看懂的話,可以繼續(xù)往下看。有形象化的解釋。
promise的用法簡單介紹一下,我覺得如果有人愿意看這篇文章,對promise的用法多多少少也了解;
new Promise((res, rej) => { try{ 執(zhí)行函數(shù); res(data) } catch(e){ rej(e); }}).then(resCb, rejCb).then(cb);
先說下我個人對promise的理解
1.promise 從表現(xiàn)形式上看,是將執(zhí)行函數(shù)的返回值通過resolve或者reject 拋出data,再在then 函數(shù)里面處理data
2.promise 可以鏈式調(diào)用then,上一個then的返回值作為下一個then中函數(shù)的實參
但實際上,promise 并非一定是在then 里面執(zhí)行的,尤其是異步的時候,理應在實例函數(shù)中執(zhí)行,才符合我們對單線程的理解。
promise簡單點說分為兩部分。一個是實例化 時候,傳入的執(zhí)行函數(shù), 另一部分為then中傳入的回調(diào)函數(shù) 這個關(guān)系就好比 監(jiān)考老師 和 學生
如果監(jiān)考老師 先到了教室,那么自然而然,學生是直接依次進入教室;(實例函數(shù)執(zhí)行較快,超過了then的聲明)
如果監(jiān)考老師 在學生們后面到,那么學生們只能按順序排隊在門口等監(jiān)考老師;(實例函數(shù)執(zhí)行較慢)
也就是說,執(zhí)行函數(shù)和then函數(shù)的聲明,先后順序并非固定(一般情況下then聲明先完成)
這個時候就需要一個狀態(tài)碼去判斷到底是哪種情況("default", "resolve" ,"reject")
為了方便理解,可以把resolve 和 reject看成同一類型
我先直接發(fā)代碼寫注釋
時間有限,本次先不考慮then 中函數(shù) 存在異步的問題
// 簡述下邏輯: //1.定義一個state 是用來判斷then 和 實例化時候傳入的函數(shù) 哪一個先完成 //也就是剛剛說的監(jiān)考老師和學生的問題。默認值為default, 默認老師沒到(實例函數(shù)未執(zhí)行完成) //2.定義resolve_ 用來存放then 中定義的方法,相當于學生排隊的過道,便于按順序執(zhí)行,reject_同理,以下不再重復 //3.定義resolveData用來記錄拋出值,也就是res(data) 中的data,作為then中方法的參數(shù) //4.在res拋出值的時候,將state改成resolve,相當于表明監(jiān)考老師到教室了 //如果resolve_隊列中已經(jīng)有定義函數(shù)就依次執(zhí)行它們,相當于如果有學生就進教室。 //5.then 方法聲明時候,檢測狀態(tài)state 是不是 default ,如果是,說明還沒有拋出值, //相當于監(jiān)考老師還沒到,學生都去排隊,加入到resolve_隊列; //如果狀態(tài)已經(jīng)不是default ,那么說明監(jiān)考老師已經(jīng)到了,學生不用排隊,直接進教室;也就是方法直接執(zhí)行 new promise_( (res, rej) => res(3)).then(data=> {console.log(data);return 6}).then(data => console.log(data))// 3,6
針對實際例子說一下
上面的例子明顯就是 res(3) 先執(zhí)行完成,然后執(zhí)行then 的函數(shù)
相當于監(jiān)考老師先到了教室,那么,then 中的定義的函數(shù)就應該直接執(zhí)行
new promise_( (res, rej) => setTimeout( () => res(3), 1000).then(data=> {console.log(data);return 6}).then(data => console.log(data))// 3,6
上面的例子明顯就是 then 先定義完成,然后res才拋出值
相當于監(jiān)考老師后到了教室,那么,then 中的定義的函數(shù)就應該默默排隊等待
因為 then 和 實例函數(shù) 兩者順序并不確定,所以 then 時候要通過state 判斷實例函數(shù) 是否執(zhí)行完成,
同時,實例函數(shù)執(zhí)行完成拋出值時,也需要檢測一下resolve_隊列,判斷then 是否已經(jīng)聲明完成。
下面是我自己寫的promise的代碼
class promise_ { constructor(func) { if(typeof func !== "function"){ throw Error("實例化中傳參必須為函數(shù)"); return; } // 判斷下是否傳入的是函數(shù) ,與邏輯無關(guān),直接往下看 this.state = "default"; //用來判斷 this.resolve_ = []; // then中reslove 的方法隊列,用來接收resolve方法 this.reject_ = []; // then中的reject 的方法隊列,用來接收reject方法 this.resolveData = null; // resolve的拋出值 this.rejectData = null; // reject的拋出值 func(this.resolve.bind(this), this.reject.bind(this)); //實例化時候傳入的函數(shù) } then(cb, errCb) { if(typeof cb !== "function" || (errCb && typeof cb !== "function")) { throw Error("then參數(shù),成功回調(diào)函數(shù),失敗回調(diào)函數(shù)"); return; } // 日常判斷是不是傳參正確,和邏輯無關(guān) switch(this.state) { // 檢測一下監(jiān)考老師來沒來教室 case "default": this.resolve_.push(cb); this.reject_.push(errCb); break;// 如果監(jiān)考老師沒到場,排隊 case "resolve": this.resolveData = cb(this.resolveData); break; // 如果監(jiān)考老師到場,直接進來,因為鏈式調(diào)用,所以執(zhí)行后把拋出值改一下,方便后面的then 用 case "reject": this.rejectData = errCb(this.rejectData); break;// 如果監(jiān)考老師到場,直接進來,因為鏈式調(diào)用,所以執(zhí)行后把拋出值改一下,方便后面的then 用 default: break; } return this; // 鏈式調(diào)用 } resolve(data) { if(!data) return; // 判斷有無參數(shù),和邏輯無關(guān) this.resolveData = data; // 設(shè)定拋出值 this.state = "resolve"; // 將狀態(tài)設(shè)置為resolve ,表示監(jiān)考老師到場了 while(this.resolve_.length) // 先進先出,依次執(zhí)行then 中函數(shù) this.resolvedata = this.resolve_.shift()(data); } reject(data) { if(!data) return; this.rejectData = data; this.state = "reject"; while(this.reject_.length) this.rejectData = this.reject_.shift()(data); } }
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/105091.html
摘要:核心的異步延遲函數(shù),用于異步延遲調(diào)用函數(shù)優(yōu)先使用原生原本支持更廣,但在的中,觸摸事件處理程序中觸發(fā)會產(chǎn)生嚴重錯誤的,回調(diào)被推入隊列但是隊列可能不會如期執(zhí)行。 淺析 Vue 2.6 中的 nextTick 方法。 事件循環(huán) JS 的 事件循環(huán) 和 任務隊列 其實是理解 nextTick 概念的關(guān)鍵。這個網(wǎng)上其實有很多優(yōu)質(zhì)的文章做了詳細介紹,我就簡單過過了。 以下內(nèi)容適用于瀏覽器端 JS,...
摘要:淺析的特點之一就是響應式,但數(shù)據(jù)更新時,并不會立即更新。盡管已經(jīng)更新,但新增的元素并不立即插入到中。實際在中,執(zhí)行了,這也是自動綁定到執(zhí)行上下文的原因。在內(nèi),使用數(shù)組保存回調(diào)函數(shù),表示當前狀態(tài),使用函數(shù)來執(zhí)行回調(diào)隊列。 Vue.nextTick 淺析 Vue 的特點之一就是響應式,但數(shù)據(jù)更新時,DOM 并不會立即更新。當我們有一個業(yè)務場景,需要在 DOM 更新之后再執(zhí)行一段代碼時,可以...
摘要:主要邏輯本質(zhì)上還是回調(diào)函數(shù)那一套。通過的判斷完成異步和同步的區(qū)分。 主要邏輯: 本質(zhì)上還是回調(diào)函數(shù)那一套。通過_subscribers的判斷完成異步和同步的區(qū)分。通過 resolve,reject -> publish -> invokeCallback -> resolve,reject的遞歸和下一條then的parent是上一條的child來完成then鏈的流轉(zhuǎn) 同步情況...
摘要:常見應用則是為了完成一些更新應用程序狀態(tài)的較小的任務,如處理的回調(diào)和的修改,以便讓這些任務在瀏覽器重新渲染之前執(zhí)行。常見應用執(zhí)行順序的實現(xiàn)需要至少一個和至少一個。 簡介 我們在上一篇 《淺析 JS 中的EventLoop 事件循環(huán)》 中提到一個 Event Queue,其實在事件循環(huán)中 queue 一共有兩種,還有一種叫 Job Queue 其中 Event Queue 在 HTML...
閱讀 3584·2021-11-15 11:36
閱讀 1077·2021-11-11 16:55
閱讀 716·2021-10-20 13:47
閱讀 3037·2021-09-29 09:35
閱讀 3468·2021-09-08 10:45
閱讀 2566·2019-08-30 15:44
閱讀 865·2019-08-30 11:10
閱讀 1442·2019-08-29 13:43