摘要:如果讓你實現(xiàn)一個你會怎么做自己實現(xiàn)的大體思路我們要明確我們需要一個異步的操作方法滿足異步回調(diào)。所以選擇加入作為實現(xiàn)的基礎(chǔ),讓函數(shù)實現(xiàn)延遲觸發(fā)。測試代碼測試第二版實現(xiàn)返回一個觸發(fā)返回一個觸發(fā)
如果讓你實現(xiàn)一個 promise ,你會怎么做? 自己實現(xiàn)promise的大體思路
我們要明確我們需要一個異步的操作方法,滿足異步回調(diào)。所以選擇加入setTimeout 作為實現(xiàn)的基礎(chǔ), 讓函數(shù)實現(xiàn)延遲觸發(fā)。
保持一個原則,控制 promise 改變狀態(tài)的只有 promise 構(gòu)造函數(shù)里的 reslove 、 reject 函數(shù)。
鏈式調(diào)用的原理, 類似jQuery,它會在調(diào)用方法后, return this. 從而形成鏈式調(diào)用。所以我們采用在調(diào)用then(fn)、 catch(fn) 后 會返回一個新的 promise 對象, 然而 這個 promise 對象 受到 它的上級promise 對象的狀態(tài)結(jié)果 和 fn 運行結(jié)果的控制。
知識點:
里面 應該 用到點 js 作用域 、 函數(shù)閉包、 繼承 、 上下文 綁定知識、引用傳遞。
cbList、rhList、 cs 這個三個, Promise 對象能直接訪問, 如果對其直接操作可能造成 程序紊亂。
代碼如有紕漏,望大家指正
var JcPromise = function (fn) { // 防止 用戶 直接 更改 state var state = "wait" // state 為 resolve 狀態(tài), 回調(diào)函數(shù)數(shù)組 var cbList = [] // state 為 reject 狀態(tài), 回調(diào)函數(shù)數(shù)組 var rjList = [] this.cbList = cbList this.rjList = rjList // this.cs = undefined // 獲取 promise 的狀態(tài) this.getState = function () { return state } /* 函數(shù)閉包,函數(shù) 定義在里面, 防止 外面用戶 直接 使用 resolve 和 reject; */ // Promise成功觸發(fā) 函數(shù) var reslove = function (data) { this.cs = data if (state !== "wait") { return } else { state = "solve" while (this.cbList.length) { cbList.shift()(data) } } } // Promise 拒絕 觸發(fā)函數(shù) var reject = function (e) { this.cs = e if (state !== "wait") { return } else { state = "reject" while (rjList.length) { rjList.shift()(e) } } } // 綁定函數(shù) conext 及 this 為當前 promise對象 reslove = reslove.bind(this) reject = reject.bind(this) // 延遲 觸發(fā) setTimeout(function () { fn(reslove, reject) }, 0) } JcPromise.prototype.then = function (fn) { var handleObj = {} var nextPromise = new JcPromise(function (r, j) { handleObj.r = r handleObj.j = j }) var fixFn = function (data) { var result = null try { result = fn(data) // 判斷result是不是 JcPromise實例。 if (result instanceof JcPromise) { result.then(function (data) { handleObj.r(data) }).catch(function (e) { handleObj.j(e) }) } else { handleObj.r(result) } } catch (e){ handleObj.j(e) } } //判斷當前狀態(tài) 如果 是 solve 直接 運行, 如果不是,酒吧 fixFn 推入 cbList 數(shù)組。 if (this.getState() === "solve") { setTimeout(function () { fixFn(this.cs) }, 0) } else { this.cbList.push(fixFn) } return nextPromise } JcPromise.prototype.catch = function (fn) { var handleObj = {} var nextPromise = new JcPromise(function (r, j) { handleObj.r = r handleObj.j = j }) var fixFn = function (e) { var result = null try { result = fn(e) if (result instanceof JcPromise) { result.then(function (data) { handleObj.r(data) }).catch(function (e) { handleObj.j(e) }) } else { handleObj.r(result) } } catch (e){ handleObj.j(e) } } if (this.getState() === "reject") { setTimeout(function () { fixFn(this.cs) }, 0) } else { this.rjList.push(fixFn) } return nextPromise }
// 測試代碼 var p = new JcPromise(function(r, j) { setTimeout(function() {r(100)}, 3000) }).then(data => { console.log("1", data) return new JcPromise((r, j) => { setTimeout(() => { r("hi") }, 3000) }) }).then(data => console.log("2", data)).then(function () { console.log("xxx", xx + 1) }).catch(e => console.log(e)).then(data => console.log(data, "end"))
demo 測試
第二版 jcPromise 實現(xiàn)
var JcPromise = (function() { function JcPromise(fn) { fn = fn || noop; var statusList = ["start", "pending", "succeed", "err"]; var cbStatus = [0, 1]; var status = statusList[0]; var data = null; var err = null; var that = this; var successFn = []; var errFn = []; function resolve(d) { data = d; that._changeStatus(2); }; function reject(e) { err = e; that._changeStatus(3); }; this.getData = function() { return data; }; this.getErr = function() { return err }; this.getStatus = function() { return status }; this._changeStatus = function(idx) { switch (status) { case statusList[2]: case statusList[3]: { return false } }; status = statusList[idx]; if (status === statusList[3]) { setTimeout(function() { that._triggerCatch(); }, 0) } if (status === statusList[2]) { setTimeout(function() { that._triggerThen(); }, 0) } }; this._pushThenCb = function(cb) { successFn.push({ status: cbStatus[0], cb: cb }); if (status === statusList[2]) { this._triggerThen(); } }; this._pushCatchCb = function(cb) { errFn.push({ status: cbStatus[0], cb: cb }); if (status === statusList[3]) { this._triggerCatch(); } }; this._triggerThen = function() { successFn.map(function(item) { if (item.status === cbStatus[0]) { item.cb(data); item.status = cbStatus[1]; } }) }; this._triggerCatch = function() { errFn.map(function(item) { if (item.status === cbStatus[0]) { item.cb(err); item.status = cbStatus[1]; } }) }; this._changeStatus(1); this.uuid = uuid++; try { fn(resolve, reject); } catch (e) { reject(e) } return this }; JcPromise.fn = JcPromise.prototype; // 返回一個promise JcPromise.fn.then = function(cb) { var promiseR = null; var promiseJ = null; var result = null; var that = this; var fn = function() { setTimeout(function() { try { var data = that.getData(); result = cb(data); if (typeof result === "object" && result !== null && result.constructor === JcPromise) { result.then(function(data) { promiseR(data) }).catch(function(e) { promiseJ(e) }) } else { promiseR(result) } } catch (e) { promiseJ(e) } }, 0); }; this._pushThenCb(fn); // 觸發(fā)promise return new JcPromise(function(r, j) { promiseR = r; promiseJ = j; }); }; // 返回一個promise JcPromise.fn.catch = function(cb) { var promiseR = null; var promiseJ = null; var result = null; var that = this; var fn = function() { setTimeout(function() { try { var data = that.getErr(); result = cb(data); if (typeof result === "object" && result !== null && result.constructor === JcPromise) { result.then(function(data) { promiseR(data) }).catch(function(e) { promiseJ(e) }) } else { promiseR(result) } } catch (e) { promiseJ(e) } }, 0) }; this._pushCatchCb(fn); // 觸發(fā)promise return new JcPromise(function(r, j) { promiseR = r; promiseJ = j; }); }; return JcPromise })();
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://www.ezyhdfw.cn/yun/93453.html
摘要:從最開始的到封裝后的都在試圖解決異步編程過程中的問題。為了讓編程更美好,我們就需要引入來降低異步編程的復雜性。寫一個符合規(guī)范并可配合使用的寫一個符合規(guī)范并可配合使用的理解的工作原理采用回調(diào)函數(shù)來處理異步編程。 JavaScript怎么使用循環(huán)代替(異步)遞歸 問題描述 在開發(fā)過程中,遇到一個需求:在系統(tǒng)初始化時通過http獲取一個第三方服務器端的列表,第三方服務器提供了一個接口,可通過...
摘要:面試題來源于網(wǎng)絡,看一下高級前端的面試題,可以知道自己和高級前端的差距。 面試題來源于網(wǎng)絡,看一下高級前端的面試題,可以知道自己和高級前端的差距。有些面試題會重復。 使用過的koa2中間件 koa-body原理 介紹自己寫過的中間件 有沒有涉及到Cluster 介紹pm2 master掛了的話pm2怎么處理 如何和MySQL進行通信 React聲明周期及自己的理解 如何...
摘要:面試的公司分別是阿里網(wǎng)易滴滴今日頭條有贊挖財滬江餓了么攜程喜馬拉雅兌吧微醫(yī)寺庫寶寶樹??低暷⒐浇挚峒覙钒俜贮c和海風教育。 (關(guān)注福利,關(guān)注本公眾號回復[資料]領(lǐng)取優(yōu)質(zhì)前端視頻,包括Vue、React、Node源碼和實戰(zhàn)、面試指導) 本人于7-8月開始準備面試,過五關(guān)斬六將,最終抱得網(wǎng)易歸,深深感受到高級前端面試的套路。以下是自己整理的面試題匯總,不敢藏私,統(tǒng)統(tǒng)貢獻出來。 面試的公司分...
閱讀 2406·2021-11-16 11:44
閱讀 715·2019-08-30 15:55
閱讀 3336·2019-08-30 15:52
閱讀 3682·2019-08-30 15:43
閱讀 2272·2019-08-30 11:21
閱讀 507·2019-08-29 12:18
閱讀 2022·2019-08-26 18:15
閱讀 531·2019-08-26 10:32