1. 术语
- Promise 是类
- promise 是一个拥有 then 方法的对象或函数,其行为符合本规范。
- thenable 是一个定义了 then 方法的对象或函数。
- value 指任何 JavaScript 的合法值(包括 undefined , thenable 和 promise)。
- exception 是使用 throw 语句抛出的一个值。
- reason 表示一个 promise 的拒绝原因。
2. 要求
2.1 Promise 状态
一个 Promise 的当前状态必须为以下三种状态中的一种:等待态(Pending)、执行态(Fulfilled)和拒绝态(Rejected)。如果是pending状态,则promise可以转换到fulfilled或rejected状态。
如果是fulfilled状态,则promise不能转换成任何其它状态,必须有一个值(value),且这个值不能被改变。
如果是rejected状态,则promise不能转换成任何其它状态,必须有一个原因(reason),且这个值不能被改变。
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class Promise {
state = PENDING
value = undefined
reason = undefined
resolve (value) {
if (this.state !== PENDING) return
this.state = FULFILLED
this.value = value
}
reject (reason) {
if (this.state !== PENDING) return
this.state = REJECTED
this.reason = reason
}
}
2.2 then 方法
一个 promise 必须提供一个 then 方法以访问其当前值、终值和据因。promise 的 then 方法接受两个参数:
promise.then(onFulfilled, onRejected)
2.2.1 onFulfilled 和 onRejected 都是可选参数
如果 onFulfilled 不是函数,其必须被忽略。如果 onRejected 不是函数,其必须被忽略。
class Promise {
// ...
then (onFulfilled, onRejected) {
if (typeof onFulfilled === 'function') {
// to do....
}
if (typeof onRejected === 'function') {
// to do....
}
}
}
2.2.2 如果 onFulfilled 是函数
它必须在 promise 完成(fulfilled)后被调用,且 promise 的 value 作为其第一个参数。它在 promise 完成(fulfilled)之前绝对不能被调用。
它不能被多次调用。
class Promise {
// ...
onFulfilledFn = undefined
resolve (value) {
if (this.state !== PENDING) return
this.state = FULFILLED
this.value = value
if (onFulfilledFn) onFulfilledFn(value)
}
then (onFulfilled) {
if (typeof onFulfilled === 'function') {
onFulfilledFn = onFulfilled
}
}
}
2.2.3 如果 onRejected 是函数
它必须在 promise 被拒绝(rejected)后被调用,且 promise 的 reason 作为其第一个参数。它在 promise 被拒绝(rejected)之前绝对不能被调用。
它不能被多次调用。
class Promise {
// ...
onRejectedFn = undefined
reject (reason) {
if (this.state !== PENDING) return
this.state = REJECTED
this.reason = reason
if (onRejectedFn) onRejectedFn(reason)
}
then (onFulfilled, onRejected) {
if (typeof onRejected === 'function') {
onRejectedFn = onRejected
}
}
}
2.2.4 onFulfilled 或者 onRejected 在执行上下文堆栈仅包含平台代码之前不得调用
nextTick是一个异步执行函数
class Promise {
// ...
resolve (value) {
nextTick(() => {
// ...
if (onFulfilledFn) onFulfilledFn(value)
})
}
reject (reason) {
nextTick(() => {
// ...
if (onRejectedFn) onRejectedFn(reason)
})
}
}
2.2.5 onFulfilled 和 onRejected 必须被作为函数调用(即没有 this 值)
class Promise {
// ...
resolve (value) {
onFulfilledFn.call(undefined, value)
}
reject (reason) {
onRejectedFn.call(undefined, reason)
}
}
2.2.6 then 方法可以被同一个 promise 调用多次
当 promise fulfilled后,所有 onFulfilled 都必须按照其注册顺序执行。当 promise rejected后,所有 onRejected 都必须按照其注册顺序执行。
class Promise {
// ...
callbacks = []
resolve (value) {
// ...
this.callbacks.forEach(cb => {
cb[0].call(undefined, value)
})
}
reject (reason) {
// ...
this.callbacks.forEach(cb => {
cb[1].call(undefined, reason)
})
}
then (onFulfilled, onRejected) {
const callback = []
if (typeof onFulfilled === 'function') {
callback[0] = onFulfilled
}
if (typeof onRejected === 'function') {
callback[1] = onRejected
}
this.callbacks.push(callback)
}
}
2.2.7 then 方法必须返回一个 promise 对象
promise2 = promise1.then(onFulfilled, onRejected);
如果 onFulfilled 或者 onRejected 返回一个值 x ,则运行下面的 Promise 解决过程:promise2.resolveWith(x)。2.3如果 onFulfilled 或者 onRejected 抛出一个异常 e ,则 promise2 必须被拒绝(rejected)并把e当作拒绝原因(reason)。
如果 onFulfilled 不是函数且 promise1 (fulfilled)成功执行, promise2 必须成功执行并返回相同的值(value)。
如果 onRejected 不是函数且 promise1 (rejected)拒绝执行, promise2 必须拒绝执行并返回相同的拒绝原因(reason)。
class Promise {
// ...
resolve (value) {
// ...
this.callbacks.forEach(cb => {
try {
let x
if (cb[0]){
x = cb[0].call(undefined, value)
} else {
x = value
}
cb[2].resolveWith.call(cb[2], x)
} catch (err) {
cb[2].reject(err)
}
})
}
reject (reason) {
this.callbacks.forEach(cb => {
try {
if (cb[1]) {
const x = cb[1].call(undefined, reason)
cb[2].resolveWith.call(cb[2], x)
} else {
cb[2].reject(reason)
}
} catch (err) {
cb[2].reject(err)
}
})
}
then (onFulfilled, onRejected) {
const callback = []
// ...
callback[2] = new Promise(() => {})
this.callbacks.push(callback)
return callback[2]
}
resolveWith (x) {
// 这里的 this 就是 promise2
// to do....
}
}
2.3 Promise 解决过程
2.3.1 如果 promise 和 x 指向同一对象,以 TypeError 为据因拒绝执行 promise
resolveWithSelf () {
this.reject(new TypeError())
}
2.3.2 如果 x 是一个 promise ,采用 promise 的状态
如果 x 处于等待态,promise 需保持为等待态直至 x 被执行或拒绝。如果 x 处于执行态,用相同的值执行 promise。
如果 x 处于拒绝态,用相同的据因拒绝 promise。
resolveWithPromise (x) {
x.then(
value => {
this.resolveWith(value)
},
reason => {
this.reject(reason)
}
)
}
2.3.3 如果 x 是一个对象或函数
把 x.then 赋值给 then。如果取 x.then 的值时抛出错误 e ,则以 e 为据因拒绝 promise。
如果 then 是函数,将 x 作为函数的作用域 this调用之。
传递两个回调函数作为参数,第一个参数叫做 resolvePromise ,第二个参数叫做 rejectPromise:
如果 resolvePromise 以值 y 为参数被调用,则运行 [[Resolve]](promise, y)。
如果 rejectPromise 以据因 r 为参数被调用,则以据因 r 拒绝 promise。
如果 resolvePromise 和 rejectPromise 均被调用,或者被同一参数调用了多次,则优先采用首次调用并忽略剩下的调用。
如果调用 then 方法抛出了异常 e:
如果 resolvePromise 或 rejectPromise 已经被调用,则忽略之,否则以 e 为原因拒绝 promise。
如果 then 不是函数,以 x 为参数执行 promise。
resolveWithThenable (x) {
let called = false
let then
try {
then = x.then
} catch (err) {
this.reject(err)
}
if (typeof then === 'function') {
try {
then.call(
x,
y => {
if (called) return
called = true
this.resolveWith(y)
},
r => {
if (called) return
called = true
this.reject(r)
}
)
} catch (err) {
if (called) return
called = true
this.reject(err)
}
} else {
this.resolve(x)
}
}
2.3.4 如果 x 不为对象或者函数,以 x 为参数执行 promise
resolveWith (x) {
if (this === x) {
this.resolveWithSelf()
} else if (x instanceof Promise) {
this.resolveWithPromise(x)
} else if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
this.resolveWithThenable(x)
} else {
this.resolve(x)
}
}
3. Promise 完整代码实现
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
let nextTick
if (typeof process !== 'undefined' && typeof process.nextTick === 'function') {
nextTick = (fn) => {
process.nextTick(fn)
}
} else if (typeof MutationObserver !== 'undefined') {
let counter = 1
nextTick = (fn) => {
const observer = new MutationObserver(fn)
const textNode = document.createTextNode(String(counter))
observer.observe(textNode, {
characterData: true
})
counter = counter + 1
textNode.data = String(counter)
}
}
class Promise {
state = PENDING
value = undefined
reason = undefined
callbacks = []
constructor (fn) {
if (typeof fn !== 'function') {
throw new Error(`Promise resolver ${fn} is not a function`)
}
fn(this.resolve.bind(this), this.reject.bind(this))
}
resolve (value) {
nextTick(() => {
if (this.state !== PENDING) return
this.state = FULFILLED
this.value = value
this.callbacks.forEach(cb => {
try {
let res
if (cb[0]){
res = cb[0].call(undefined, value)
} else {
// 2.2.7.3 onFulfilled不是一个函数时 value要传给下一个then
res = value
}
cb[2].resolveWith.call(cb[2], res)
} catch (err) {
cb[2].reject(err)
}
})
})
}
reject (reason) {
nextTick(() => {
if (this.state !== PENDING) return
this.state = REJECTED
this.reason = reason
this.callbacks.forEach(cb => {
try {
if (cb[1]) {
const res = cb[1].call(undefined, reason)
cb[2].resolveWith.call(cb[2], res)
} else {
cb[2].reject(reason)
}
} catch (err) {
cb[2].reject(err)
}
})
})
}
then (onFulfilled, onRejected) {
const callback = []
if (typeof onFulfilled === 'function') {
if (this.state === FULFILLED) {
// 2.2.4 promise.then中嵌套promise.then,如果已经 fulfilled 就直接调用onFulfilled
// 因为在当前tick中,嵌套的promise.then还未存放到callbacks里面
nextTick(() => {
const value = onFulfilled.call(undefined, this.value)
// 处理后续
callback[2].resolveWith.call(callback[2], value)
})
} else {
callback[0] = onFulfilled
}
}
if (typeof onRejected === 'function') {
if (this.state === REJECTED) {
// 2.2.4 promise.then中嵌套promise.then,如果已经 rejected 就直接调用 onRejected
// 因为在当前tick中,嵌套的promise.then还未存放到callbacks里面
nextTick(() => {
const value = onRejected.call(undefined, this.reason)
// 处理后续
callback[2].resolveWith.call(callback[2], value)
})
} else {
callback[1] = onRejected
}
}
callback[2] = new Promise(() => {})
this.callbacks.push(callback)
return callback[2]
}
resolveWithSelf () {
this.reject(new TypeError())
}
resolveWithPromise (x) {
x.then(
value => {
this.resolveWith(value)
},
reason => {
this.reject(reason)
}
)
}
resolveWithThenable (x) {
let called = false
let then
try {
then = x.then
} catch (err) {
this.reject(err)
}
if (typeof then === 'function') {
try {
then.call(
x,
y => {
// 递归处理thenable,处理完了this.resolve才是出口
if (called) return
called = true
this.resolveWith(y)
},
r => {
if (called) return
called = true
this.reject(r)
}
)
} catch (err) {
if (called) return
called = true
this.reject(err)
}
} else {
this.resolve(x)
}
}
resolveWith (x) {
if (this === x) {
this.resolveWithSelf()
} else if (x instanceof Promise) {
this.resolveWithPromise(x)
} else if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
this.resolveWithThenable(x)
} else {
this.resolve(x)
}
}
}
github源码地址:https://github.com/xingxinglail/promise