一、术语
1、promise 是具有 then 方法的对象或函数,期行为符合此规范
2、thenable 是定义 then 方法的对象或函数
3、value 是任意合法的 js值
4、excpetion 是使用 throw 语句抛出的值
5、reason 是表示 promise 为什么被 rejected 的值
二、Promise 状态
一个 promise 必须处于三种状态之一
1、pending
当promise处于 pending 状态时,状态可以转换为 fulfilled 或 rejected
2、fulfilled
- 2.1 状态不能改变
- 2.2 value 能改变
3、rejected
- 3.1 状态不能改变
- 3.2 value 能改变
三、then 方法
promise 的 then 方法接收两个参数:
promise.then(onFulfilled, onRejected)
1、onFulfilled 和 onRejected 都是可选参数
- 1.1 如果
onFulfilled==不是函数==,则在对应状态中直接执行resolve(this.value) - 1.2 如果
onRjected==不是函数==,则在对应状态中直接执行reject(this.reason)
2、then 方法,必须返回一个 promise 对象
- 2.1 如果
onFulfilled或onRejected返回一个x值,执行 ==Promise解决程序==[[Resolve]](promise2,x),promise2 会进入 onFulfilled 状态 - 2.2 如果
onFullfilled或onRejected抛出一个异常,promise2 必须拒绝(rejected),并把 异常信息 当做原因
四、Promise解决程序 (难点)
Promise 解决程序是一个抽象操作,它以一个 promise 和一个值(x)作为输入,我们将其表示为 [[Resolve]](promise,x)。
1、如果 x 和 promise 相等,则抛出一个错误,作为拒绝 promised的原因。
2、如果 x 是一个 promise,则采用它的状态
- 2.1 如果 x 处于 pending 状态,直到 x 状态改变
- 2.2 如果 x 是 fulfilled 状态,用 相同的值 完成 promise
- 2.3 如果 x 是 rejected 状态,用相同的原因 拒绝 promise
3、如果,x是一个对象或函数 - 3.1 声明一个变量 then,将 then 赋值为 x.then - 3.2 如果检索属性 x.then 导致抛出异常 e,则 e 作为原因拒绝 promise - 3.3 如果 then 是一个函数,用 x 作为 this 调用它。then 方法的参数有两个回调函数,第一个参数 resolvePromise,第二个参数 rejectPromise - 3.4 如果 then 不是一个函数,则用 x 作为 value 完成 promise
4、如果 x 不是一个函数或对象,用 x 作为 valu 完成 promise.
- Promise 解决程序 resolvePromise 代码实现
const resolvePromise = (promise, x, resolve, reject) => {
// 1、如果 x 和 promise 相等,则抛出一个错误,作为拒绝 promise 的原因
if (promise === x) {
return reject(new TypeError("Chaning cycle detected for promise"));
}
// 2、如果 x 是一个 promise,则采用它的状态
if (x instanceof MyPromise) {
if(x.status === PENDING) {
// - 2.1 如果 x 处于 pending 状态,直到 x 状态改变
x.then(resolve, reject);
} else if(x.status === FULFILLED) {
// - 2.2 如果 x 是 fulfilled 状态,用 相同的值 完成 promise
resolve(x.value);
} else if(x.status === REJECTED) {
// 2.3 如果 x 是 rejected 状态,用相同的原因 拒绝 promise
reject(x.reason);
}
return
}
// 3、如果 x 是一个 Object 或 Function
if ((typeof x === "object" && x !== null) || typeof x === "function") {
try {
let isCalled = false; // 标记 x.then 中的回调是否被调用过
const then = x.then;
if (typeof x === "function") {
// 当 x.then 是 Function 时,就将其视为 MyPromise 对象
// 3.1 执行 then 方法,并将 this 绑定为 x,传入两个回调函数
then.call(
x,
(val) => {
if (isCalled) return;
isCalled = true;
// 3.2 需要递归调用 MyPromise 中 resolve 出去的值,也就是这里的 val
resolvePromise(promise, val, resolve, reject);
},
(r) => {
if (isCalled) return;
isCalled = true;
// 3.3 对于 reject,直接将其 reason 给 reject 出去即可
reject(r);
}
);
} else {
resolve(x);
}
} catch (error) {
if (isCalled) return;
isCalled = true;
reject(error);
}
} else {
// 4、如果 x 不是一个函数或对象,则 x 作为 value 完成 promise
resolve(x);
}
};
五、完整 Promise 实现代码
const Pending = "PENDING";
const Fulfilled = "FULFILLED";
const Rejected = "Rejected";
class MyPromise {
constructor(executor) {
this.value = null;
this.reason = null;
this.status = Pending;
this.onFulfilledCallbacks = [];
this.onRejectedCallbacks = [];
const resolve = (val) => {
queueMicrotask(() => {
if (this.status !== Pending) return;
this.status = Fulfilled;
this.value = val;
this.onFulfilledCallbacks.forEach((cb) => {
cb(this.value);
});
});
};
const reject = (reason) => {
queueMicrotask(() => {
if (this.status !== Pending) return;
this.status = Rejected;
this.reason = reason;
this.onRejectedCallbacks.forEach((cb) => {
cb(this.reason);
});
});
};
try {
executor(resolve, reject);
} catch (error) {
reject(error);
}
}
then(onFullfilled, onRejected) {
const promise2 = new MyPromise((resolve, reject) => {
if (this.status === Pending) {
this.onFulfilledCallbacks.push(() => {
try {
if (typeof onFullfilled !== "function") {
resolve(this.value);
} else {
const res = onFullfilled(this.value);
resolvePromise(promise2, res, resolve, reject);
}
} catch (error) {
reject(error);
}
});
this.onRejectedCallbacks.push(() => {
try {
if (typeof onRejected !== "function") {
reject(this.reason);
} else {
const res = onRejected(this.reason);
resolvePromise(promise2, res, resolve, reject);
}
} catch (error) {
reject(error);
}
});
}
if (this.status === Fulfilled) {
queueMicrotask(() => {
try {
if (typeof onFullfilled !== "function") {
resolve(this.value);
} else {
const res = onFullfilled(this.value);
resolvePromise(promise2, res, resolve, reject);
}
} catch (error) {
reject(error);
}
});
}
if (this.status === Rejected) {
queueMicrotask(() => {
try {
if (typeof onRejected !== "function") {
reject(this.reason);
} else {
const res = onRejected(this.reason);
resolvePromise(promise2, res, resolve, reject);
}
} catch (error) {
reject(error);
}
});
}
});
return promise2;
}
catch(onRejected) {
return this.then(undefined, onRejected);
}
finally(onFinished) {
return this.then(onFinished, onFinished);
}
static all(promises) {
if (!Array.isArray(promises)) {
return new TypeError("请传入promise数组!");
}
return new MyPromise((resolve, reject) => {
let len = 0;
const resArr = [];
promises.forEach((p, index) => {
p.then(
(res) => {
resArr[index] = res;
len++;
if (len === promises.length) {
resolve(resArr);
}
},
(err) => {
reject(err);
}
);
});
});
}
static race(promises) {
if (!Array.isArray(promises)) {
return new TypeError("请传入promise数组!");
}
return new MyPromise((resolve, reject) => {
promises.forEach((p) => {
p.then(
(res) => {
resolve(res);
},
(reason) => {
reject(reason);
}
);
});
});
}
static allSettled(promises) {
if (!Array.isArray(promises)) {
return new TypeError("请传入promise数组!");
}
return new MyPromise((resolve, reject) => {
let len = 0;
const resArr = [];
const onResolve = () => {
if (len === promises.length) {
resolve(resArr);
}
};
promises.forEach((p, index) => {
p.then(
(res) => {
resArr[index] = {
status: "fulfilled",
value: res,
};
len++;
onResolve();
},
(err) => {
resArr[index] = {
status: "rejected",
value: err,
};
len++;
onResolve();
}
);
});
});
}
static any(promises) {
if (!Array.isArray(promises)) {
return new TypeError("请传入promise数组!");
}
return new MyPromise((resolve, reject) => {
let len = 0;
const resArr = [];
const onRejected = () => {
if (len === promises.length) {
reject(resArr);
}
};
promises.forEach((p, index) => {
p.then(
(res) => {
resolve(res);
},
(err) => {
resArr[index] = err;
len++;
onRejected();
}
);
});
});
}
static resolve(v) {
// 1、如果参数是 Promise 实例,那么Promise.resolve将不做任何修改、原封不动地返回这个实例。
if (v instanceof MyPromise) {
return v;
}
return new MyPromise(function (resolve) {
resolve(parameter);
});
}
static reject(v) {
return new MyPromise((resolve, reject) => {
reject(v);
});
}
}
const resolvePromise = (promise, x, resolve, reject) => {
// 1、如果 x 和 promise 相等,则抛出一个错误,作为拒绝 promise 的原因
if (promise === x) {
return reject(new TypeError("Chaning cycle detected for promise"));
}
// 2、如果 x 是一个 promise,则采用它的状态
if (x instanceof MyPromise) {
if (x.status === Pending) {
// - 2.1 如果 x 处于 pending 状态,直到 x 状态改变
x.then((val) => {
resolvePromise(promise, val, resolve, reject);
}, reject);
} else if (x.status === Fulfilled) {
// - 2.2 如果 x 是 fulfilled 状态,用 相同的值 完成 promise
resolve(x.value);
} else if (x.status === Rejected) {
// 2.3 如果 x 是 rejected 状态,用相同的原因 拒绝 promise
reject(x.reason);
}
return;
}
// 3、如果 x 是一个 Object 或 Function
if ((typeof x === "object" && x !== null) || typeof x === "function") {
let isCalled = false; // 标记 x.then 中的回调是否被调用过
try {
const then = x.then;
if (typeof then === "function") {
// 当 x.then 是 Function 时,就将其视为 MyPromise 对象
// 3.1 执行 then 方法,并将 this 绑定为 x,传入两个回调函数
then.call(
x,
(val) => {
if (isCalled) return;
isCalled = true;
// 3.2 需要递归调用 MyPromise 中 resolve 出去的值,也就是这里的 val
resolvePromise(promise, val, resolve, reject);
},
(r) => {
if (isCalled) return;
isCalled = true;
// 3.3 对于 reject,直接将其 reason 给 reject 出去即可
reject(r);
}
);
} else {
resolve(x);
}
} catch (error) {
if (isCalled) return;
isCalled = true;
reject(error);
}
} else {
// 4、如果 x 不是一个函数或对象,则 x 作为 value 完成 promise
resolve(x);
}
};
六、Promise A+ 规范测试
- 1、 下载插件
npm i promises-aplus-tests -D
- 2 在
package.json添加命令
"scripts": {"test": "promises-aplus-tests ./promise-test.js [你的测试文件]",},
- 3、在测试文件中添加必要代码
MyPromise.defer = MyPromise.deferred = function () {
let dfd = {};
dfd.promise = new MyPromise((resolve, reject) => {
dfd.resolve = resolve;
dfd.reject = reject;
});
return dfd;
};
module.exports = MyPromise;
- 4、在终端中执行测试命令
npm run test
参考文文章: