摘要:本文參考了實踐教程實現這個視頻,并添加了自己的一些想法。三種狀態必須是函數初始狀態是返回值完成時調用的方法,這里做了容錯拒絕時調用的方法再次運行,正確打印出結果。
本文參考了Node.js 實踐教程 - Promise 實現這個視頻,并添加了自己的一些想法。
首先來看 Promise 的構造:
// 這里用 Prometheus 代替 Promise let p = new Prometheus((resolve, reject) => { resolve("hello") })
下面我們來實現它:
// 三種狀態 const PENDING = Symbol() const FULFILLED = Symbol() const REJECTED = Symbol() function Prometheus (fn) { // fn 必須是函數 if (typeof fn !== "function") { throw new Error("fn must be a function!") } let state = PENDING // 初始狀態是 PENDING let value = null // 返回值 function fulfill (result) { state = FULFILLED value = result } // 完成時調用的方法,這里做了容錯 function resolve (result) { try { fulfill(result) } catch (err) { reject(err) } } // 拒絕時調用的方法 function reject (error) { state = REJECTED value = error } fn(resolve, reject) }
第二步,實現 then 方法:
let p = new Prometheus((resolve, reject) => { resolve("hello") }) p.then(val => { console.log(val) })
// 三種狀態 const PENDING = Symbol() const FULFILLED = Symbol() const REJECTED = Symbol() function Prometheus (fn) { // fn 必須是函數 if (typeof fn !== "function") { throw new Error("fn must be a function!") } let state = PENDING // 初始狀態是 PENDING let value = null // 返回值 function fulfill (result) { state = FULFILLED value = result } // 完成時調用的方法,這里做了容錯 function resolve (result) { try { fulfill(result) } catch (err) { reject(err) } } // 拒絕時調用的方法 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) })
直接運行上面的代碼發現控制臺沒有打印出 hello,原因是 Prometheus 里的代碼是異步執行,導致記下來執行 then 方法的時候,state 是 PENDING,后面再執行 resolve 的時候就不會走到 onFulfill 了,所以我們要在 then 方法里添加 state 為 PENDING 的分支判斷,把 onFulfill 和 onReject 存到一個變量中:
// 三種狀態 const PENDING = Symbol() const FULFILLED = Symbol() const REJECTED = Symbol() function Prometheus (fn) { // fn 必須是函數 if (typeof fn !== "function") { throw new Error("fn must be a function!") } let state = PENDING // 初始狀態是 PENDING let value = null // 返回值 let hanler = {} function fulfill (result) { state = FULFILLED value = result handler.onFulfill(result) } // 完成時調用的方法,這里做了容錯 function resolve (result) { try { fulfill(result) } catch (err) { reject(err) } } // 拒絕時調用的方法 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) }
異步實現了,我們再回過頭看看同步是否正常運行:
let p = new Prometheus((resolve, reject) => { resolve("hello") }) p.then(val => { console.log(val) })
發現報錯信息:
TypeError: handler.onReject is not a function
因為同步執行的時候,fulfill 里 handler 是 {},所以會報錯。
// 三種狀態 const PENDING = Symbol() const FULFILLED = Symbol() const REJECTED = Symbol() function Prometheus (fn) { // fn 必須是函數 if (typeof fn !== "function") { throw new Error("fn must be a function!") } let state = PENDING // 初始狀態是 PENDING let value = null // 返回值 let handler = {} function fulfill (result) { state = FULFILLED value = result next(handler) } // 完成時調用的方法,這里做了容錯 function resolve (result) { try { fulfill(result) } catch (err) { reject(err) } } // 拒絕時調用的方法 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) }
現在同步也可以正常運行了,接下來看看多個 then 鏈式調用:
let p = new Prometheus((resolve, reject) => { resolve("hello") }) p.then(val => { console.log(val) return "world" }).then(val => { console.log(val) })
執行代碼會發現如下報錯信息:
TypeError: Cannot read property "then" of undefined
原因是 then 方法沒有返回 Promise。
// 三種狀態 const PENDING = Symbol() const FULFILLED = Symbol() const REJECTED = Symbol() function Prometheus (fn) { // fn 必須是函數 if (typeof fn !== "function") { throw new Error("fn must be a function!") } let state = PENDING // 初始狀態是 PENDING let value = null // 返回值 let handler = {} function fulfill (result) { state = FULFILLED value = result next(handler) } // 完成時調用的方法,這里做了容錯 function resolve (result) { try { fulfill(result) } catch (err) { reject(err) } } // 拒絕時調用的方法 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) }
再次運行,正確打印出結果。
到此,一個非常簡單的 Promise 就實現了,當然,這里其實還有很多細節沒有考慮,具體還要參考 Promise/A+。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/84458.html
從零實現一個簡易的 Promise 所有問題都可以通過加一層中間層來解決。 Promises/A+ 簡易的,不做廢話直接開始 :) const p = new Promise((resolve, reject)=>{ // 如果操作成功則調用 resolve 并傳入 value // 如果操作失敗則調用 reject 并傳入 reason }); 通常我們都會使用上述方法獲取 P...
摘要:所以,這篇文章我會帶大家從零開始,手寫一個基本能用的。首先,規定對象是一個構造函數,用來生成實例。然后,這個構造函數接受一個函數作為參數,該函數的兩個參數分別是和。對象通過自身的狀態,來控制異步操作。 剛開始寫前端的時候,處理異步請求經常用callback,簡單又順手。后來寫著寫著就拋棄了callback,開始用promise來處理異步問題。promise寫起來確實更加優美,但由于缺乏...
摘要:是什么在規范中,是一個類,它的構造函數接受一個函數。在這種情況下,是但處于狀態。與一起使用關鍵字會暫停執行一個函數,直到等待的變成狀態。此外,會一直等待調用直到下一個時序。 原文:Write Your Own Node.js Promise Library from Scratch作者:code_barbarian Promise 已經是 JavaScript 中異步處理的基石,回調...
摘要:從零開始搭建同構應用四搭建完善上一篇我們使用了的方式測試了,這篇文章來講如何在前文的基礎上搭建一個,實現真正意義上的。至此,一個簡單的框架已經搭建完成,剩下的工作就是結合工作需要,在里面添磚加瓦啦。 從零開始搭建React同構應用(四):搭建Koa Server & 完善SSR 上一篇我們使用了CLI的方式測試了SSR,這篇文章來講如何在前文的基礎上搭建一個Koa Server,實現真...
閱讀 3596·2020-12-03 17:42
閱讀 2768·2019-08-30 15:54
閱讀 2223·2019-08-30 15:44
閱讀 571·2019-08-30 14:08
閱讀 970·2019-08-30 14:00
閱讀 1103·2019-08-30 13:46
閱讀 2784·2019-08-29 18:33
閱讀 2886·2019-08-29 14:11