摘要:本文參考了實(shí)踐教程實(shí)現(xiàn)這個(gè)視頻,并添加了自己的一些想法。三種狀態(tài)必須是函數(shù)初始狀態(tài)是返回值完成時(shí)調(diào)用的方法,這里做了容錯(cuò)拒絕時(shí)調(diào)用的方法再次運(yùn)行,正確打印出結(jié)果。
本文參考了Node.js 實(shí)踐教程 - Promise 實(shí)現(xiàn)這個(gè)視頻,并添加了自己的一些想法。
首先來(lái)看 Promise 的構(gòu)造:
// 這里用 Prometheus 代替 Promise let p = new Prometheus((resolve, reject) => { resolve("hello") })
下面我們來(lái)實(shí)現(xiàn)它:
// 三種狀態(tài) const PENDING = Symbol() const FULFILLED = Symbol() const REJECTED = Symbol() function Prometheus (fn) { // fn 必須是函數(shù) if (typeof fn !== "function") { throw new Error("fn must be a function!") } let state = PENDING // 初始狀態(tài)是 PENDING let value = null // 返回值 function fulfill (result) { state = FULFILLED value = result } // 完成時(shí)調(diào)用的方法,這里做了容錯(cuò) function resolve (result) { try { fulfill(result) } catch (err) { reject(err) } } // 拒絕時(shí)調(diào)用的方法 function reject (error) { state = REJECTED value = error } fn(resolve, reject) }
第二步,實(shí)現(xiàn) then 方法:
let p = new Prometheus((resolve, reject) => { resolve("hello") }) p.then(val => { console.log(val) })
// 三種狀態(tài) const PENDING = Symbol() const FULFILLED = Symbol() const REJECTED = Symbol() function Prometheus (fn) { // fn 必須是函數(shù) if (typeof fn !== "function") { throw new Error("fn must be a function!") } let state = PENDING // 初始狀態(tài)是 PENDING let value = null // 返回值 function fulfill (result) { state = FULFILLED value = result } // 完成時(shí)調(diào)用的方法,這里做了容錯(cuò) function resolve (result) { try { fulfill(result) } catch (err) { reject(err) } } // 拒絕時(shí)調(diào)用的方法 function reject (error) { state = REJECTED value = error } this.then = function (onFulfill, onReject) { switch (state) { case FULFILLED: onFulfill(value) break case REJECTED: onReject(value) break } } fn(resolve, reject) }
第三步,在 Promise 里使用異步
let p = new Prometheus((resolve, reject) => { setTimeout(() => { resolve("hello") }, 0) }) p.then(val => { console.log(val) })
直接運(yùn)行上面的代碼發(fā)現(xiàn)控制臺(tái)沒有打印出 hello,原因是 Prometheus 里的代碼是異步執(zhí)行,導(dǎo)致記下來(lái)執(zhí)行 then 方法的時(shí)候,state 是 PENDING,后面再執(zhí)行 resolve 的時(shí)候就不會(huì)走到 onFulfill 了,所以我們要在 then 方法里添加 state 為 PENDING 的分支判斷,把 onFulfill 和 onReject 存到一個(gè)變量中:
// 三種狀態(tài) const PENDING = Symbol() const FULFILLED = Symbol() const REJECTED = Symbol() function Prometheus (fn) { // fn 必須是函數(shù) if (typeof fn !== "function") { throw new Error("fn must be a function!") } let state = PENDING // 初始狀態(tài)是 PENDING let value = null // 返回值 let hanler = {} function fulfill (result) { state = FULFILLED value = result handler.onFulfill(result) } // 完成時(shí)調(diào)用的方法,這里做了容錯(cuò) function resolve (result) { try { fulfill(result) } catch (err) { reject(err) } } // 拒絕時(shí)調(diào)用的方法 function reject (error) { state = REJECTED value = error handler.onReject(error) } this.then = function (onFulfill, onReject) { switch (state) { case FULFILLED: onFulfill(value) break case REJECTED: onReject(value) break case PENDING: handler = { onFulfill, onReject } } } fn(resolve, reject) }
異步實(shí)現(xiàn)了,我們?cè)倩剡^(guò)頭看看同步是否正常運(yùn)行:
let p = new Prometheus((resolve, reject) => { resolve("hello") }) p.then(val => { console.log(val) })
發(fā)現(xiàn)報(bào)錯(cuò)信息:
TypeError: handler.onReject is not a function
因?yàn)橥綀?zhí)行的時(shí)候,fulfill 里 handler 是 {},所以會(huì)報(bào)錯(cuò)。
// 三種狀態(tài) const PENDING = Symbol() const FULFILLED = Symbol() const REJECTED = Symbol() function Prometheus (fn) { // fn 必須是函數(shù) if (typeof fn !== "function") { throw new Error("fn must be a function!") } let state = PENDING // 初始狀態(tài)是 PENDING let value = null // 返回值 let handler = {} function fulfill (result) { state = FULFILLED value = result next(handler) } // 完成時(shí)調(diào)用的方法,這里做了容錯(cuò) function resolve (result) { try { fulfill(result) } catch (err) { reject(err) } } // 拒絕時(shí)調(diào)用的方法 function reject (error) { state = REJECTED value = error next(handler) } function next({ onFulfill, onReject }) { switch (state) { case FULFILLED: onFulfill && onFulfill(value) break case REJECTED: onReject && onReject(value) break case PENDING: handler = { onFulfill, onReject } } } this.then = function (onFulfill, onReject) { next({onFulfill, onReject}) } fn(resolve, reject) }
現(xiàn)在同步也可以正常運(yùn)行了,接下來(lái)看看多個(gè) then 鏈?zhǔn)秸{(diào)用:
let p = new Prometheus((resolve, reject) => { resolve("hello") }) p.then(val => { console.log(val) return "world" }).then(val => { console.log(val) })
執(zhí)行代碼會(huì)發(fā)現(xiàn)如下報(bào)錯(cuò)信息:
TypeError: Cannot read property "then" of undefined
原因是 then 方法沒有返回 Promise。
// 三種狀態(tài) const PENDING = Symbol() const FULFILLED = Symbol() const REJECTED = Symbol() function Prometheus (fn) { // fn 必須是函數(shù) if (typeof fn !== "function") { throw new Error("fn must be a function!") } let state = PENDING // 初始狀態(tài)是 PENDING let value = null // 返回值 let handler = {} function fulfill (result) { state = FULFILLED value = result next(handler) } // 完成時(shí)調(diào)用的方法,這里做了容錯(cuò) function resolve (result) { try { fulfill(result) } catch (err) { reject(err) } } // 拒絕時(shí)調(diào)用的方法 function reject (error) { state = REJECTED value = error next(handler) } function next({ onFulfill, onReject }) { switch (state) { case FULFILLED: onFulfill && onFulfill(value) break case REJECTED: onReject && onReject(value) break case PENDING: handler = { onFulfill, onReject } } } this.then = function (onFulfill, onReject) { return new Prometheus((resolve, reject) => { next({ onFulfill: val => { resolve(onFulfill(val)) }, onReject: err => { reject(onReject(err)) } }) }) } fn(resolve, reject) }
再次運(yùn)行,正確打印出結(jié)果。
到此,一個(gè)非常簡(jiǎn)單的 Promise 就實(shí)現(xiàn)了,當(dāng)然,這里其實(shí)還有很多細(xì)節(jié)沒有考慮,具體還要參考 Promise/A+。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/84458.html
從零實(shí)現(xiàn)一個(gè)簡(jiǎn)易的 Promise 所有問(wèn)題都可以通過(guò)加一層中間層來(lái)解決。 Promises/A+ 簡(jiǎn)易的,不做廢話直接開始 :) const p = new Promise((resolve, reject)=>{ // 如果操作成功則調(diào)用 resolve 并傳入 value // 如果操作失敗則調(diào)用 reject 并傳入 reason }); 通常我們都會(huì)使用上述方法獲取 P...
摘要:所以,這篇文章我會(huì)帶大家從零開始,手寫一個(gè)基本能用的。首先,規(guī)定對(duì)象是一個(gè)構(gòu)造函數(shù),用來(lái)生成實(shí)例。然后,這個(gè)構(gòu)造函數(shù)接受一個(gè)函數(shù)作為參數(shù),該函數(shù)的兩個(gè)參數(shù)分別是和。對(duì)象通過(guò)自身的狀態(tài),來(lái)控制異步操作。 剛開始寫前端的時(shí)候,處理異步請(qǐng)求經(jīng)常用callback,簡(jiǎn)單又順手。后來(lái)寫著寫著就拋棄了callback,開始用promise來(lái)處理異步問(wèn)題。promise寫起來(lái)確實(shí)更加優(yōu)美,但由于缺乏...
摘要:是什么在規(guī)范中,是一個(gè)類,它的構(gòu)造函數(shù)接受一個(gè)函數(shù)。在這種情況下,是但處于狀態(tài)。與一起使用關(guān)鍵字會(huì)暫停執(zhí)行一個(gè)函數(shù),直到等待的變成狀態(tài)。此外,會(huì)一直等待調(diào)用直到下一個(gè)時(shí)序。 原文:Write Your Own Node.js Promise Library from Scratch作者:code_barbarian Promise 已經(jīng)是 JavaScript 中異步處理的基石,回調(diào)...
摘要:只有動(dòng)手,你才能真的理解作者的構(gòu)思的巧妙只有動(dòng)手,你才能真正掌握一門技術(shù)持續(xù)更新中項(xiàng)目地址求求求源碼系列跟一起學(xué)如何寫函數(shù)庫(kù)中高級(jí)前端面試手寫代碼無(wú)敵秘籍如何用不到行代碼寫一款屬于自己的類庫(kù)原理講解實(shí)現(xiàn)一個(gè)對(duì)象遵循規(guī)范實(shí)戰(zhàn)手摸手,帶你用擼 Do it yourself!!! 只有動(dòng)手,你才能真的理解作者的構(gòu)思的巧妙 只有動(dòng)手,你才能真正掌握一門技術(shù) 持續(xù)更新中…… 項(xiàng)目地址 https...
摘要:從零開始搭建同構(gòu)應(yīng)用四搭建完善上一篇我們使用了的方式測(cè)試了,這篇文章來(lái)講如何在前文的基礎(chǔ)上搭建一個(gè),實(shí)現(xiàn)真正意義上的。至此,一個(gè)簡(jiǎn)單的框架已經(jīng)搭建完成,剩下的工作就是結(jié)合工作需要,在里面添磚加瓦啦。 從零開始搭建React同構(gòu)應(yīng)用(四):搭建Koa Server & 完善SSR 上一篇我們使用了CLI的方式測(cè)試了SSR,這篇文章來(lái)講如何在前文的基礎(chǔ)上搭建一個(gè)Koa Server,實(shí)現(xiàn)真...
閱讀 3679·2020-12-03 17:42
閱讀 2829·2019-08-30 15:54
閱讀 2307·2019-08-30 15:44
閱讀 627·2019-08-30 14:08
閱讀 1028·2019-08-30 14:00
閱讀 1156·2019-08-30 13:46
閱讀 2848·2019-08-29 18:33
閱讀 3130·2019-08-29 14:11