摘要:如果讓你實(shí)現(xiàn)一個(gè)你會(huì)怎么做自己實(shí)現(xiàn)的大體思路我們要明確我們需要一個(gè)異步的操作方法滿(mǎn)足異步回調(diào)。所以選擇加入作為實(shí)現(xiàn)的基礎(chǔ),讓函數(shù)實(shí)現(xiàn)延遲觸發(fā)。測(cè)試代碼測(cè)試第二版實(shí)現(xiàn)返回一個(gè)觸發(fā)返回一個(gè)觸發(fā)
如果讓你實(shí)現(xiàn)一個(gè) promise ,你會(huì)怎么做? 自己實(shí)現(xiàn)promise的大體思路
我們要明確我們需要一個(gè)異步的操作方法,滿(mǎn)足異步回調(diào)。所以選擇加入setTimeout 作為實(shí)現(xiàn)的基礎(chǔ), 讓函數(shù)實(shí)現(xiàn)延遲觸發(fā)。
保持一個(gè)原則,控制 promise 改變狀態(tài)的只有 promise 構(gòu)造函數(shù)里的 reslove 、 reject 函數(shù)。
鏈?zhǔn)秸{(diào)用的原理, 類(lèi)似jQuery,它會(huì)在調(diào)用方法后, return this. 從而形成鏈?zhǔn)秸{(diào)用。所以我們采用在調(diào)用then(fn)、 catch(fn) 后 會(huì)返回一個(gè)新的 promise 對(duì)象, 然而 這個(gè) promise 對(duì)象 受到 它的上級(jí)promise 對(duì)象的狀態(tài)結(jié)果 和 fn 運(yùn)行結(jié)果的控制。
知識(shí)點(diǎn):
里面 應(yīng)該 用到點(diǎn) js 作用域 、 函數(shù)閉包、 繼承 、 上下文 綁定知識(shí)、引用傳遞。
cbList、rhList、 cs 這個(gè)三個(gè), Promise 對(duì)象能直接訪問(wèn), 如果對(duì)其直接操作可能造成 程序紊亂。
代碼如有紕漏,望大家指正
var JcPromise = function (fn) { // 防止 用戶(hù) 直接 更改 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ù) 定義在里面, 防止 外面用戶(hù) 直接 使用 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 為當(dāng)前 promise對(duì)象 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實(shí)例。 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) } } //判斷當(dāng)前狀態(tài) 如果 是 solve 直接 運(yùn)行, 如果不是,酒吧 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 }
// 測(cè)試代碼 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 測(cè)試
第二版 jcPromise 實(shí)現(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; // 返回一個(gè)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; }); }; // 返回一個(gè)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)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/93453.html
摘要:從最開(kāi)始的到封裝后的都在試圖解決異步編程過(guò)程中的問(wèn)題。為了讓編程更美好,我們就需要引入來(lái)降低異步編程的復(fù)雜性。寫(xiě)一個(gè)符合規(guī)范并可配合使用的寫(xiě)一個(gè)符合規(guī)范并可配合使用的理解的工作原理采用回調(diào)函數(shù)來(lái)處理異步編程。 JavaScript怎么使用循環(huán)代替(異步)遞歸 問(wèn)題描述 在開(kāi)發(fā)過(guò)程中,遇到一個(gè)需求:在系統(tǒng)初始化時(shí)通過(guò)http獲取一個(gè)第三方服務(wù)器端的列表,第三方服務(wù)器提供了一個(gè)接口,可通過(guò)...
摘要:面試題來(lái)源于網(wǎng)絡(luò),看一下高級(jí)前端的面試題,可以知道自己和高級(jí)前端的差距。 面試題來(lái)源于網(wǎng)絡(luò),看一下高級(jí)前端的面試題,可以知道自己和高級(jí)前端的差距。有些面試題會(huì)重復(fù)。 使用過(guò)的koa2中間件 koa-body原理 介紹自己寫(xiě)過(guò)的中間件 有沒(méi)有涉及到Cluster 介紹pm2 master掛了的話pm2怎么處理 如何和MySQL進(jìn)行通信 React聲明周期及自己的理解 如何...
摘要:面試的公司分別是阿里網(wǎng)易滴滴今日頭條有贊挖財(cái)滬江餓了么攜程喜馬拉雅兌吧微醫(yī)寺庫(kù)寶寶樹(shù)??低暷⒐浇挚峒覙?lè)百分點(diǎn)和海風(fēng)教育。 (關(guān)注福利,關(guān)注本公眾號(hào)回復(fù)[資料]領(lǐng)取優(yōu)質(zhì)前端視頻,包括Vue、React、Node源碼和實(shí)戰(zhàn)、面試指導(dǎo)) 本人于7-8月開(kāi)始準(zhǔn)備面試,過(guò)五關(guān)斬六將,最終抱得網(wǎng)易歸,深深感受到高級(jí)前端面試的套路。以下是自己整理的面試題匯總,不敢藏私,統(tǒng)統(tǒng)貢獻(xiàn)出來(lái)。 面試的公司分...
閱讀 2323·2021-11-16 11:44
閱讀 668·2019-08-30 15:55
閱讀 3303·2019-08-30 15:52
閱讀 3646·2019-08-30 15:43
閱讀 2226·2019-08-30 11:21
閱讀 463·2019-08-29 12:18
閱讀 1985·2019-08-26 18:15
閱讀 502·2019-08-26 10:32