任何符合promise规范的对象和函数都可以成为Promise。
以下内容参考自promise A plus 规范,地址:https://promisesaplus.com/
基本术语
- Promise:是一个具有then方法的对象或函数,其行为符合Promises/A+规范。
- thenadble:是一个定义了then方法的对象或函数。
- value:指任何JavaScript的合法值(包括undefined,thenable,和promise)。
- exception:使用throw抛出的一个值。
- reason:说明Promise状态改为rejected的原因。
要求
1. Promise的状态
一个Promise的当前状态必须是一下三种状态中的一种:pending,fullfilled,rejected。
- 当处于pending状态时,Promise可以转换为fullfilled状态或rejected状态。
- 当处于fullilled状态时,Promise的状态不能被更改,且必须有一个不可变的值。
- 当处于rejected状态时,Promise的状态不能被更改,且必须有一个不可变的原因。
2. then方法
Promise必须提供一个then方法,可以查看其当前或最终的值或者原因。
Promise的then方法接收两个可选参数:Promise.then(onFullfilled, onRejected)。
2.1 如果onFullfilled或onRejected不是函数,则需要忽略他们。
2.2 如果onFullfilled是一个函数:
- Promise的状态变为fullfilled前其不能被调用。
- Promise的状态变为fullfilled后必须被调用,且接收Promise的结果作为第一个参数。
最多被调用一次。
2.3 如果onRejected是一个函数:
- Promise的状态变为rejected前其不能被调用。
- Promise的状态变为rejected状态后必须被调用,且接收Promise的原因作为第一个参数。
最多被调用一次。
2.4 当执行上下文堆栈仅包含“platform code”之前,不能调用onFullFilled和onRejected。
这里“platform code”是指引擎、环境和Promise参数函数代码。在实际应用中,这一要求确保onFulfilled和onRejected在调用事件循环后以新的堆栈异步执行。这可以通过“宏任务”机制(如setTimeout或setImmediate)实现,也可以通过“微任务”机制(如MutationObserver或process.nextTick实现。
2.5 onFulfilled 和 onRejected 必须被作为普通函数调⽤(即⾮实例化调⽤,这样函数内部 this ⾮严格模式下指向 window)。
2.6 then ⽅法可以被同⼀个 promise 调⽤多次。
- 当 promise 成功执⾏时,所有 onFulfilled 需按照其注册顺序依次回调。
- 当 promise 被拒绝执⾏时,所有的 onRejected 需按照其注册顺序依次回调。
2.7 then ⽅法必须返回⼀个新的 promise 对象: promise2 = promise1.then(onFulfilled, onRejected);
- 只要 onFulfilled 或者 onRejected 返回⼀个值 x ,promise2 都会进⼊ resolved 状态。
- 如果 onFulfilled 或者 onRejected 抛出⼀个异常 e ,则 promise2 会进入rejected状态,并返回拒绝原因 e。
- 如果 onFulfilled 不是函数且 promise1 状态变为fullfilled, promise2 会进入fullfilled状态并返回相同的值。
- 如果 onRejected 不是函数且 promise1 状态变为rejected, promise2 会进入rejected状态并返回相同的拒绝原因。
3. Promise的解析过程
promise解析过程是一个抽象操作,输入一个promise和一个值,我们将其表示为[[Resolve]](promise,x)。如果x是一个tenable,它试图使promise采用x的状态。否则,它就将x值包装成一个Promise。
3.1 如果promise和x指向同一个对象,Promise将进入rejected状态,并返回一个TypeError作为拒绝原因。
3.2 如果 x 为 promise:
- 如果 x 处于pending状态, promise 需保持为pending直⾄ x 被执⾏或拒绝。
- 如果 x 处于fullfilled状态,⽤相同的值执⾏ promise。
- 如果 x 处于rejected态,⽤相同的拒绝原因拒绝promise。
3.3 如果 x 为对象或函数(不常见):
- 首先尝试执行x.then,
- 如果取x.then时抛出错误e,则以e为原因拒绝Promise。
- 如果then是函数,将x作为函数作用域调用。传递两个回调函数作为参数,第一个叫做resolvePromise,第二个叫做rejectPromise:
- 如果 resolvePromise 以值 y 为参数被调⽤,则运⾏[[Resolve]](promise,y)。
- 如果 rejectPromise 以拒绝原因 r 为参数被调⽤,则以拒绝原因 r 拒绝 promise。
- 如果 resolvePromise 和 rejectPromise 均被调⽤,或者被同⼀参数调⽤了多次,则优先采⽤⾸次调⽤并忽略其他的调⽤。
- 如果调⽤ then ⽅法抛出了异常 e:
- 如果 resolvePromise 或 rejectPromise 已经被调⽤,则忽略。
- 否则以 e 为拒绝原因拒绝 promise。
- 如果then不是函数,以x为参数将Promise变为fullfilled状态。
3.4 如果 x 不是对象或者函数,以x为参数将Promise变为fullfilled状态(重要且常见)。
------------------------------------------------------------手写Promise来啦---------------------------------------------------------------
------------------------------------------------------------手写Promise来袭---------------------------------------------------------------
class MyPromise {
constructor(handleFn) {
// Promise的状态
this.PromiseState = "pending";
// Promise的结果
this.PromiseValue = null;
// 画重点!!!这两个list是为了将下一个Promise与当前Promise相关联
this._toNextResolve = [];
this._toNextReject = [];
// Promise接收的函数参数
handleFn(this.triggerResolve.bind(this), this.triggerReject.bind(this));
}
// resolve处理
triggerResolve(data) {
// 这里使用setTimeout的原因是:确保resolve处理函数在handleFn所处的事件循环后以新的堆栈异步执行。(参见:2.4)
setTimeout(() => {
// Promise的状态不是pending时,不能被修改状态。(参见:1)
if (this.PromiseState !== "pending") return;
// 修改Promise的状态和值
this.PromiseState = "fullfilled";
this.PromiseValue = data;
this._toNextResolve.forEach(item => item(data));
this._toNextResolve = [];
}, 0);
}
// reject处理,同上
triggerReject(data) {
setTimeout(() => {
if (this.PromiseState !== "pending") return;
this.PromiseState = "rejected";
this.PromiseValue = data;
this._toNextReject.forEach(item => item(data));
this._toNextReject = [];
}, 0);
}
// 将多个Promise包装成一个新的Promise实例,并在所有异步操作执行完后执行回调
static all(list) {
const result = [];
let count = 0;
return new MyPromise(function(resolve, reject) {
for (let [i, MyPromiseInstance] of list.entries()) {
MyPromiseInstance.then(
res => {
result[i] = res;
count++;
if (count === list.length) resolve(result);
},
err => {
reject(err);
}
);
}
});
}
static race(list) {
return new MyPromise(function(resolve, reject) {
for (let [i, MyPromiseInstance] of list.entries()) {
MyPromiseInstance.then(
res => {
resolve(res);
},
err => {
reject(err);
}
);
}
});
}
// static resolve(val) {
// return new MyPromise(resolve=>resolve(val));
// }
// static reject(val) {
// return new MyPromise(resolve=>{}, reject=>reject(val));
// }
}
MyPromise.prototype.then = function(onResolved, onRejected) {
const { PromiseState, PromiseValue } = this;
// then方法必须返回一个Promise对象。(参见:2.7)
return new MyPromise((onNextResolved, onNextRejected) => {
function onLastFullFilled(val) {
if (typeof onResolved !== "function") {
// 如果onResolved不是函数,则需要忽略他。(参见:2.1)
onNextResolved(val);
} else {
const res = onResolved(val);
if (res && typeof res.then === "function") {
// 若res 是一个 promise
res.then(onNextResolved);
} else {
// 若res 非 promise,则直接执行下一个 onNextResolved
onNextResolved(res);
}
}
}
function onLastRejected(val) {
if (typeof onRejected !== "function") {
// 如果onRejected不是函数,则需要忽略他。(参见:2.1)
onNextRejected(val);
} else {
const res = onRejected(val);
if (res && typeof res.then === "function") {
// 若res 是一个 promise
res.then(onNextRejected);
} else {
// 若res 非 promise,则直接执行下一个 onNextRejected
onNextRejected(res);
}
}
}
switch (PromiseState) {
case "pending": {
this._toNextResolve.push(onLastFullFilled);
this._toNextReject.push(onLastRejected);
break;
}
}
});
};
const p1 = function() {
return new MyPromise(function(resolve, reject) {
setTimeout(function() {
const random = Math.random() * 10;
if (random > 5) {
resolve("已完成1:" + random);
} else {
reject("已拒绝1:" + random);
}
}, 1000);
});
};
const p2 = function() {
return new MyPromise(function(resolve, reject) {
const random = Math.random() * 10;
resolve("已完成2:" + random);
});
};
const p3 = function() {
return new MyPromise(function(resolve, reject) {
const random = Math.random() * 10;
resolve("已完成3:" + random);
});
};
p1().then(
res => {
console.log('then方法:');
console.log(res);
},
err => {
console.log('then方法:');
console.log(err);
}
);
MyPromise.all([p1(), p2(), p3()]).then(
res => {
console.log('all方法:');
console.log(res);
},
err => {
console.log('all方法:');
console.log(err);
}
);
MyPromise.race([p1(), p2(), p3()]).then(
res => {
console.log('race方法:');
console.log(res);
},
err => {
console.log('race方法:');
console.log(err);
}
);