实现Promise 或者是all、race、any等
问题1:
Promise/A+ 约定了哪些规范?问题2:
手动实现 Promise 的过程中都遇到过哪些问题?Promise/A+ 规范
术语
- promise:是一个具有then 方法的对象或者函数,它的行为符合该规范
- thenable:是一个定义了then 方法的对象或函数
- value:可以是任何一个合法的 JavaScript 的值(包括undefined、thenable 或 promise)
- exception:是一个异常,是在 Promise 里面可以用 throw 语句抛出来的值
- reason:是一个 Promise 里 reject 之后返回的拒绝原因
状态描述
一个 Promise 有三种状态:pending、fulfilled 和 rejected
当状态为 pending 状态时,即可以转换为 fulfilled 或者 rejected 其中之一
当状态为 fulfilled 状态时,就不能转换为其他状态了,必须返回一个不能再改变的值
当状态为 rejected 状态时,同样也不能转换为其他状态,必须有一个原因的值也不能改变
then 方法
一个 Promise 必须拥有一个 then 方法来访问它的值或者拒绝原因
promise.then(onFulfilled, onRejected)
onFulfilled 和 onRejected 特性
如果 onFulfilled 是函数,则当 Promise 执行结束之后必须被调用,最终返回值为 value,其调用次数不可超过一次
而 onRejected 除了最后返回的是 reason 外,其他方面和 onFulfilled 在规范上的表述基本一样
多次调用
then 方法其实可以被一个 Promise 调用多次且必须返回一个 Promise 对象
promise2 = promise1.then(onFulfilled, onRejected);
实现一个符合 Promise/A+ 规范的 Promise
构造函数
Promise 构造函数接受一个 executor 函数
executor 函数执行完同步或异步操作后,调用它的两个参数 resolve 和 reject
try {
module.exports = Promise;
}
function Promise(executor) {
var self = this
self.status = 'pending' // Promise 当前的状态
self.data = undefined // Promise 的值
self.onResolvedCallback = [] // Promise resolve时的回调函数集
self.onRejectedCallback = [] // Promise reject时的回调函数集
function resolve(value) {
if (value instanceof Promise) {
return value.then(resolve, reject);
}
}
setTimeout(function() { // 异步执行所有的回调函数
if (self.status === 'pending') {
self.status = 'resolved'
self.data = value
for (var i = 0; i < self.onResolvedCallback.length; i++) {
self.onResolvedCallback[i](value);
}
}
})
function reject(reason) {
setTimeout(function() { // 异步执行所有的回调函数
if (self.status === 'pending') {
self.status = 'rejected'
self.data = reason
for (var i = 0; i < self.onRejectedCallback.length; i++) {
self.onRejectedCallback[i](reason);
}
}
})
}
try { // 考虑到执行过程中有可能出错,所以我们用try/catch 块给包起
executor(resolve, reject) // 执行 executor
} catch(e) {
reject(e)
}
}
function resolvePromise(promise2, x, resolve, reject) {
var then
var thenCalledOrThrow = false
if (promise2 === x) {
return reject(new TypeError('Chaning cycle detected for promise!'))
}
if (x instanceof Promise) {
if (x.status === 'pending') {
x.then(function(v) {
resolvePromise(promise2, v, resolve, reject)
}, reject)
} else {
x.then(resolve, reject)
}
return
}
if ((x !== null) && ((typeof x === 'object') || (typeof x === 'function'))) {
try {
then = x.then
if (typeof then === 'function') {
then.call(x, function rs(y) {
if (thenCalledOrThrow) return
thenCalledOrThrow = true
return resolvePromise(promise2, y, resolve, reject)
}, function rj(r) {
if (thenCalledOrThrow) return
thenCalledOrThrow = true
return reject(r)
})
} else {
resolve(x)
}
} catch (e) {
if (thenCalledOrThrow) return
thenCalledOrThrow = true
return reject(e)
}
} else {
resolve(x)
}
}
实现 then 方法
then 方法是 Promise 执行完之后可以拿到 value 或者 reason 的方法并且还要保持then 执行之后
返回的依旧是一个 Promise 方法,还要支持多次调用
// then 方法接收两个参数 onResolved 和 onRejected,分别为 Promise 成功或失败后的回调
Promise.prototype.then = function(onResolved, onRejected) {
var self = this;
var promise2
// 根据标准,如果then 的参数不是function,则需要忽略它
onResolved = typeof onResolved === 'function' ? onResolved : function(v) { return v }
onRejected = typeof onRejected === 'function' ? onRejected : function(r) { return r }
if (self.status === 'resolved') {
// 如果 promise1 的状态已经确定并且是 resolved,我们调用 onResolved,考虑到有可能 throw,所以还需要将其包在try/catch块里
return promise2 = new Promise(function(resolve, reject) {
setTimeout(function() { // 异步执行 onResolved
try {
var x = onResolved(self, data)
resolvePromise(promise2, x, resolve, reject)
} catch (reason) {
reject(reason)
}
})
// try {
// var x = onResolved(self, data)
// if (x instanceof Promise) {
// // 如果 onResolved 的返回值是一个 Promise 对象,直接取它的结果作为 Promise2 的结果
// x.then(resolve, reject)
// }
// resolve(x) // 否则,以它的返回值作为 promise2 的结果
// } catch (e) {
// reject(e); // 如果出错,以捕获到的错误作为promise2 的结果
// }
})
}
// 此处与前一个 if 块的逻辑几乎相同,区别在于所调用的是 onRejected 函数
if (self.status === 'rejected') {
return promise2 = new Promise(function(resolve, reject) {
setTimeout(function() { // 异步执行 onRejected
try {
var x = onRejected(self.data)
resolvePromise(promise2, x, resolve, reject)
} catch (reason) {
reject(reason)
}
})
// try {
// var x = onRejected(self.data)
// if (x instanceof Promise) {
// x.then(resolve, reject);
// }
// } catch (e) {
// reject(e);
// }
})
}
if (self.status === 'pending') {
// 如果当前的 Promise 还处于 pending 状态,我们并不是确定调用 onResolved 还是 onRejected,只能等到 Promise 的状态确定后,才能确定如何处理
return promise2 = new Promise(function(resolve, reject) {
self.onResolvedCallback.push(function(value) {
try {
var x = onResolved(self.data)
resolvePromise(promise2, x, resolve, reject)
// if (x instanceof Promise) {
// x.then(resolve, reject)
// }
} catch (r) {
reject(r)
}
})
self.onRejectedCallback.push(function(reason) {
try {
var x = onRejected(self.data)
resolvePromise(promise2, x, resolve, reject)
// if (x instanceof Promise) {
// x.then(resolve, reject)
// }
} catch (r) {
reject(re)
}
})
})
}
}
Promise.prototype.catch = function (onRejected) {
return this.then(null, onRejected)
}
// 测试
Promise.deferred = Promise.defer = function() {
var dfd = {}
dfd.promise = new Promise(function(resolve, reject) {
dfd.resolve = resolve
dfd.reject = reject
})
return dfd
}
Promise 并不是 JS 一开始存在的标准,如果你使用的某一个库中封装了一个 Promise 的实现,想象一下如果它不能跟你自己使用的 Promise 实现交互的情况,其实还是会有问题的