本文参考了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://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。