实现
一、Promise
1.1 状态特性
Promise 中有三种状态分别为: 等待Pending、成功Fulfilled、失败Rejected。状态的修改只能是 pending
到 rejected
或者 pending
到 resolved
,且状态是不可逆的。
Pending
-->Fulfilled
Pending
-->Rejected
一旦状态改变不可更改
const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";
1.2 状态变更
Promise
的状态可以通过以下三种方式变更:
-
resolve()
: 将Promise的Pending
状态置为Fulfilled
-
reject()
: 用于将Promise的Pending
状态置为Rejected
-
throw()
: 用于将Promise的Pending
状态置为Rejected
二、Promise.constructor
2.1 执行器
Promise 是一个类,在实例化这个类的时候,需要传递一个回调函数进去,回调函数也成为执行器 。 new Promise()
有一个回调函数需要实现,且回调函数需要有两个参数,所以构造函数需要有一个参数executor
,之后执行器(executor)
会立即执行
语法
class Promise{
constructor(executor){
executor();
}
}
三、Promise.prototype.resolve
resolve 用于将Promise的Pending
状态置为Fulfilled
实现
resolve = (value) => {
if (this.status !== PENDING) {
return;
}
this.status = FULFILLED;
this.value = value;
this.fulfilledCallback.forEach((callback) => {
callback();
});
};
注意: 由于resolve
是Promise
类内部调用,resolve
中的this
必须要指向Promise
实例。所以最好使用箭头函数,避免引起this指向的问题。
四、Promise.prototype.reject
reject 用于将Promise的Pending
状态置为Rejected
reject = (reason) => {
if (this.status !== PENDING) {
return;
}
this.status = REJECTED;
this.reason = reason;
this.rejectedCallback.forEach((callback) => {
callback();
});
};
五、Promise.prototype.then
Promise.prototype.then
创建新的Promise实例对象并返回
5.1 思路
回调穿透: 如果 then
方法中没有成功 / 失败的回调函数的话, 让 Promise
的值一直被传递下去
onFulfilled =
typeof onFulfilled === "function" ? onFulfilled : (value) => value;
onRejected =
typeof onRejected === "function"
? onRejected
: (reason) => {
throw reason;
};
链式调用: 返回一个 Promise
对象, 让 Promise
可以链式调用
return new Promise()
Promise
执行器: 执行的工作如下:
-
**旧的
Promise
在执行器中同步调用resolve
,此时旧的Promise
状态为成功调用成功的回调函数,判断回调函数的返回值。执行Promise
**的解决过程 -
旧的
Promise
在执行器中同步调用reject
,此时**旧的Promise
状态为失败调用失败的回调函数,判断回调函数的返回值。执行Promise
**的解决过程 -
旧的
Promise
在执行器中异步调用resolve
或者reject
,此时**旧的Promise
状态为等待,则存储成功与失败回调函数。执行Promise
**的解决过程
为什么触发回调函数要放到setTimeout
里面呢?
答: 使用 setTimeout
执行回调函数是为了确保 then
方法上注册的回
调 onFulfilled
和 onRejected
能够异步执行,且应该在 then
方法被调用的那一
轮事件循环之后的新执行栈中执行。
5.2 实现
then(onFulfilled, onRejected) {
onFulfilled =
typeof onFulfilled === "function" ? onFulfilled : (value) => value;
onRejected =
typeof onRejected === "function"
? onRejected
: (reason) => {
throw reason;
};
const newPromise = new Promise((resolve, reject) => {
if (this.status === FULFILLED) {
setTimeout(() => {
try {
const value = onFulfilled(this.value);
resolution(newPromise, value, resolve, reject);
} catch (error) {
reject(error);
}
});
} else if (this.status === REJECTED) {
setTimeout(() => {
try {
const reason = onRejected(this.reason);
resolution(newPromise, reason, resolve, reject);
} catch (error) {
reject(error);
}
});
} else {
this.fulfilledCallback.push(() => {
setTimeout(() => {
try {
const value = onFulfilled(this.value);
resolution(newPromise, value, resolve, reject);
} catch (error) {
reject(error);
}
});
});
this.rejectedCallback.push(() => {
setTimeout(() => {
try {
const reason = onRejected(this.reason);
resolution(newPromise, reason, resolve, reject);
} catch (error) {
reject(error);
}
});
});
}
});
return newPromise;
}
5.3 问题
问题一、为什么需要重新创建一个Promise
实例对象呢?返回自身的Promise
对象(this
)不可以吗?
答: 返回一个新的Promise对象而不是返回自身,这样是为了防止循环引用。
问题二、为什么then
方法不像jQuery
那样返回this
而是要重新返回一个新的promise
对象?
答: 如果then
返回了this
,那么promise2
就和promise1
的状态同步,promise1
状态变更后,promise2
就没办法接受后面异步操作进行的状态变更
六、Promise.prototype.catch
6.1 思路
异常穿透return new Promise(()=>{})
** 以及 Promise.then(()=>{})
回调函数内部发生的错误具有 冒泡 的性质, 会一直向后传递,直到被捕获为止。也就是说: 错误总是被下一个 catch
语句捕获。因此, Promise
的异常穿透有以下特点:
-
Promise
回调函数内部任何操作出现问题, 不会传递到外层代码, 不会退出进程, 不会中断外部程序执行 -
Promise
失败回调 获取不到自身 成功回调 抛出的错误, 因此, 我们可以在最后指定失败的回调 -
前面任何操作出现了异常, 都会直接传递到最后失败的回调中进行处理。会跳过 抛出错误 到 失败回调 的中间环节。
-
在失败的回调处理完成后, 返回的还是
Promise
, 因此可以在失败的回调后继续.then
或者.catch
。
6.2 实现
catch(onRejected) {
return this.then(undefined, onRejected);
}
七、Promise.prototype.then resolution
function resolution(promise, x, resolve, reject) {
if (promise === x) {
return reject(new TypeError("promise 相同,造成了循环引用"));
}
let called;
if ((typeof x === "object" && x !== null) || typeof x === "function") {
try {
const then = x.then;
if (typeof then === "function") {
then.call(
x,
(y) => {
if (called) {
return;
}
called = true;
resolution(promise, y, resolve, reject);
},
(reason) => {
if (called) {
return;
}
called = true;
reject(reason);
}
);
} else {
resolve(x);
}
} catch (error) {
if (called) {
return;
}
called = true;
reject(error);
}
} else {
resolve(x);
}
}
八、Promise.prototype.finally
Promise.prototype.finally
用于指定 Promise
对象变更状态之后执行的操作。无论是 Promise
最后的状态变为 fulfilled
还是 rejected
。 这避免了同样的语句需要在**then()和catch()**中各写一次的情况。最后返回一个新的 Promise
对象
8.1 实现
Promise
类中实现
finally(callback) {
return this.then(
(value) => {
return Promise.resolve(callback()).then(() => value);
},
(reason) => {
return Promise.reject(callback()).then(() => {
throw reason;
});
}
);
}
Promise
类外实现
Promise.prototype.finally = function (callback) {
const promise = this.constructor;
return this.then(
(value) => promise.resolve(callback()).then(() => value),
(error) =>
promise.resolve(callback()).then(() => {
throw error;
})
);
};
注意: 由于reject
是Promise
类内部调用,reject
中的this
必须要指向Promise
实例,所以最好使用箭头函数,避免引起this指向的问题。
九、Promise.all
Promise.all
方法用于将多个 Promise
实例(如果某一个元素不是 Promise
实例, 会调用 Promise.resolve
将该元素转化为 Promise
实例。
),包装成一个新的 Promise
实例。 新的 Promise
实例的状态由传入的多个 Promise
实例的状态 决定。分两种情况:
-
传入的多个
Promise
实例状态都变为Fulfilled
: 新的Promise
实例的状态变为Fulfilled
。此时, 多个Promise
实例的返回值组成一个数组,传递给新的Promise
实例的回调函数 -
传入的多个
Promise