术语
- promise:是具有符合本规范的
then方法的对象或函数。 - thenable:是定义了
then方法的对象或函数。 - value:是任何合法的
JavaScript值(包括undefined、thenable或promise)。 - exception:是使用
throw语句抛出的值。 - reason:是表示
promise被拒绝的原因的值。
要求
Promise的状态
- 一个
promise必须处于以下三种状态之一:pending(等待)、fulfilled(已完成)或rejected(已拒绝)。 - 当且仅当
promise处于pending(等待)时,才可被修改。 - 处于
fulfilled状态下的promise不可转换为其他状态,且必须有一个不可更改的值(value)。 - 处于
rejected状态下的promise不可转换为其他状态,且必须有一个不可更改的原因(reason)。
then方法
promise必须提供一个then方法以访问其当前或最终的值或原因。
一个promise的then方法接受两个参数:
promise.then(onFulfilled, onRejected)
-
onFulfilled:-
onFulfilled是可选参数。 -
我们期望
onFulfilled是一个函数,如果onFulfilled不是一个函数,它必须被忽略。 -
它必须在
promise实现后调用,并以promise的值作为其第一个参数。 -
在
promise实现之前不得调用它。 -
它不能被调用多次。
-
onRejected:
-
onRejected是可选参数。 -
我们期望
onRejected是一个函数,如果onRejected不是一个函数,它必须被忽略。 -
它必须在
promise实现后调用,并以promise的原因作为其第一个参数。 -
在
promise被拒绝之前不得调用它。 -
它不能被调用多次。
-
onFulfilled或onRejected不能在执行上下文堆栈中只包含平台代码之前调用。 -
onFulfilled和onRejected必须作为函数被调用(即没有this值)。 -
then方法可以在同一个promise上多次调用。
- 如果/当
promise被实现时,所有相应的onFulfilled回调函数必须按照它们发起then调用的顺序执行。 - 如果/当
promise被拒绝时,所有相应的onRejected回调函数必须按照它们发起then调用的顺序执行。
- 如果/当
-
then方法必须返回一个promise。-
promise2 = promise1.then(onFulfilled, onRejected); -
如果
onFulfilled或onRejected返回一个值x,则运行Promise Resolution Procedure[[Resolve]](promise2, x)。 -
如果
onFulfilled或onRejected抛出异常e,则promise2必须以e作为原因被拒绝。 -
如果
onFulfilled不是一个函数且promise1被实现,则promise2必须以与promise1相同的值被实现。 -
如果
onRejected不是一个函数且promise1被拒绝,则promise2必须以与promise1相同的原因被拒绝。
-
Promise解决过程
Promise解决过程是一个抽象操作,接受一个promise和一个值作为输入,我们将其表示为[[Resolve]](promise, x)。如果x是一个thenable,它尝试使promise采用x的状态,假设x至少在某种程度上像一个promise。否则,它使用值x来实现promise。
对thenable的处理允许promise实现进行互操作,只要它们暴露符合Promises/A+的then方法。它还允许Promises/A+实现通过合理的then方法来“吸收”不符合规范的实现。
运行[[Resolve]](promise, x),执行以下步骤:
- 如果
promise和x引用同一个对象,则以TypeError为原因拒绝promise。 - 如果
x是一个promise,采用其状态- 如果
x处于待定状态,则promise必须保持待定状态,直到x被实现或拒绝。 - 如果/当
x被实现时,用相同的值实现promise。 - 如果/当
x被拒绝时,用相同的原因拒绝promise。
- 如果
- 否则,如果
x是一个对象或函数:- 让
then为x.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。
- 让
- 如果
x不是对象或函数,则用x来实现promise。
如果一个promise被解决为一个参与循环thenable链的thenable,以至于递归的[[Resolve]](promise, thenable)最终再次调用[[Resolve]](promise, thenable),按照上述算法进行将导致无限递归。实现可以选择性地检测到这种递归并以一个信息丰富的TypeError为原因拒绝promise,但不是必须的。
代码实现
class Promise {
static PENDING = 'pending';
static FULFILLED = 'fulfilled';
static REJECTED = 'rejected';
constructor(executor) {
this.PromiseState = Promise.PENDING
this.value = undefined
this.reason = undefined
this.onFulfilledCallbacks = []
this.onRejectedCallbacks = []
const resolve = value => {
if(this.PromiseState === Promise.PENDING){
this.PromiseState = Promise.FULFILLED
this.value = value
this.onFulfilledCallbacks.forEach(callback=>callback(this.value))
}
}
const reject = reason => {
if(this.PromiseState === Promise.PENDING){
this.PromiseState = Promise.REJECTED
this.reason = reason
this.onRejectedCallbacks.forEach(callback=>callback(this.reason))
}
}
try{
executor(resolve,reject)
}catch (e) {
reject(e)
}
}
then(onFulfilled, onRejected){
if(typeof onFulfilled !== 'function'){
onFulfilled = value => {
return value
}
}
if(typeof onRejected !== 'function'){
onRejected = reason => {
throw reason
}
}
let promise2 = new Promise((resolve,reject)=>{
if(this.PromiseState === Promise.FULFILLED){
setTimeout(()=>{
try{
const x = onFulfilled(this.value)
Promise.resolvePromise(promise2,x,resolve,reject)
}catch (e) {
reject(e)
}
})
}
if(this.PromiseState === Promise.REJECTED){
setTimeout(()=>{
try{
const x = onRejected(this.reason)
Promise.resolvePromise(promise2,x,resolve,reject)
}catch (e) {
reject(e)
}
})
}
if(this.PromiseState === Promise.PENDING){
this.onFulfilledCallbacks.push((value)=>{
setTimeout(() => {
try{
const x = onFulfilled(value)
Promise.resolvePromise(promise2,x,resolve,reject)
}catch (e) {
reject(e)
}
})
})
this.onRejectedCallbacks.push((reason)=>{
setTimeout(() => {
try{
const x = onRejected(reason)
Promise.resolvePromise(promise2,x,resolve,reject)
}catch (e) {
reject(e)
}
})
})
}
})
return promise2
}
catch(onRejected){
return this.then(null,onRejected)
}
static resolvePromise(promise2,x,resolve,reject) {
if(promise2 === x){
reject(new TypeError('Chaining cycle detected for promise'))
}
if(x instanceof Promise){
x.then(value => {
Promise.resolvePromise(promise2,value,resolve,reject)
}, reason => {
reject(reason)
})
}else if(x !== null && (typeof x === 'object' || typeof x === 'function')){
let called = false
try{
const then = x.then
if(typeof then === 'function'){
then.call(x,value => {
if(called) return
called = true
Promise.resolvePromise(promise2, value, resolve, reject)
}, reason => {
if(called) return
called = true
reject(reason)
})
}else{
if(called) return
called = true
resolve(x)
}
}catch (e) {
if(called) return
called = true
reject(e)
}
}else{
resolve(x)
}
}
}
promise中的其他方法
static resolve(value){
if(!value){
return new Promise((resolve)=>{
resolve()
})
}
if(value instanceof Promise){
return value
}
if(value && typeof value === 'object' && typeof value.then === 'function'){
return new Promise((resolve,reject)=>{
value.then(resolve,reject)
})
}
return new Promise((resolve)=>{
resolve(value)
})
}
static reject(value){
return new Promise((resolve,reject)=>{
reject(value)
})
}
static all(promises){
return new Promise((resolve,reject)=>{
try{
promises = Array.from(promises)
}catch (e) {
reject(new TypeError('参数必须是一个数组'))
return
}
let count = promises.length
let results = new Array(count)
if(count === 0){
resolve(results)
return
}
promises.forEach((promise,index)=>{
Promise.resolve(promise).then(res=>{
results[index] = res
count--
if(count === 0){
resolve(results)
return
}
}).catch(err=>{
reject(err)
return
})
})
})
}
static race(promises){
return new Promise((resolve,reject)=>{
try{
promises = Array.from(promises)
}catch (e) {
reject(new TypeError('参数必须是一个数组'))
return
}
if(promises.length === 0){
return resolve([])
}
promises.forEach((promise,index)=>{
Promise.resolve(promise).then(res=>{
resolve(res)
return
}).catch(err=>{
reject(err)
return
})
})
})
}
如何判断代码是否符合promises/A+规范
在你的代码中添加(将promise替换为你自己定义的类名)
Promise.defer = Promise.deferred = function(){
let dfd = {};
dfd.promise = new Promise((resolve, reject)=>{
dfd.resolve = resolve;
dfd.reject = reject;
});
return dfd;
}
module.exports = Promise
在控制台运行指令npm run test