跳到主要内容

认识

2023年06月16日
柏拉文
越努力,越幸运

一、认识


Promise 提供了一种比传统回调或事件机制更直观、更易于维护的异步处理方式,能有效解决 回调地狱 和错误处理分散的问题。Promise 遵循 Promise/A+ 规范,确保其行为具有可预测性和一致性。它使得异步操作的链式调用和错误传递变得简单。

Promise 变更状态, Promise 的状态可以通过以下三种方式变更: resolve(): 将 PromisePending状态置为Fulfilled; reject(): 用于将 PromisePending状态置为Rejected; throw(): 用于将 PromisePending 状态置为 Rejected

Promise 异常穿透: Promise 内部任何操作出错(无论是在构造函数中,还是 then 回调内抛出异常),都会导致当前 Promise 被拒绝,而这个错误会沿着链 冒泡, 直到遇到下一个 catch 回调。因此, 无论在链的哪个环节出错, 最终都可以在链的末尾统一捕获并处理。但是, 如果在 then 的成功回调中抛出异常, 这个异常不会被同一个 then 的失败回调捕获, 而是传递给后续的 catchthen 的失败分支。这使得错误处理更集中, 也要求开发者在链式调用的最后一定要有 catch, 以防止未处理的异常(某些环境下未处理的 Promise 拒绝可能会导致警告或者程序崩溃)。

Promise 异常捕获: 如果 Promise 被拒绝且没有 catch 捕获, 在 Node.js 和现代浏览器中可能会触发 unhandledRejection 事件。如果 Promise 被拒绝但是被 catch 捕获, 会触发 rejectionHandled 事件。

二、语法


new Promise((resolve,reject)=>{
if(true){
resolve(1);
}else{
reject(2);
}
}).then(res=>{
console.log(res);
}).catch(error=>{
console.log(error)
});

三、特点


3.1 状态

Promise对象代表一个异步操作,有三种状态:

  • pending(进行中)

  • fulfilled(已成功)

  • rejected(已失败)

Promise 状态一旦改变, 就不会在变。Promise 的状态改变,只有两种可能: 从 pending 变为 fulfilled 和从 pending 变为 rejected。只要这两种情况发生, 状态就凝固了,不会再变了。

Promise 改变状态的方式有以下三种:

  • resolve(): 将PromisePending状态置为Fulfilled

  • reject(): 用于将PromisePending状态置为Rejected

  • throw(): 用于将PromisePending状态置为Rejected

3.2 弊端

  1. 无法取消 Promise,一旦新建 new Promise 就会立即执行,无法中途取消。

  2. 如果不设置回调函数, Promise 内部抛出的错误,不会反应到外部。

  3. 当处于 pending 状态时, 无法得知目前进展到了哪一阶段(刚刚开始还是即将完成)

四、检测


描述 检测环境是否支持 Promise

function isNative(Ctor){
return typeof Ctor === 'function' && /native code/.test(Ctor.toString());
}

function isSupportPromise(){
return typeof Promise !== 'undefined' && isNative(Promise);
}

四、问题


4.1 如何中断 Promise 的执行?

一、使用 AbortController 中断: 首先创建了一个新的 AbortController 实例和对应的 signal。然后,在 Promise 内部,我们设置了一个计时器来模拟异步操作,并在5秒后解决 Promise。同时,我们监听 signal 上的 abort 事件,以便在 Promise 被中止时清除计时器并拒绝 Promise。最后,我们使用 controller.abort() 方法来中止 Promise

const controller = new AbortController();
const signal = controller.signal;

const promise = new Promise((resolve, reject) => {
const timeoutId = setTimeout(() => {
resolve("Promise resolved");
}, 5000);

// 监听 signal 是否被中止
signal.addEventListener("abort", () => {
clearTimeout(timeoutId);
reject(new Error("Promise aborted"));
});
});

// 中止 Promise
controller.abort();

二、使用闭包和标记变量: 我们将 cancel 方法定义为一个变量, 在 Promise 构造函数内部创建, 然后将其赋值给 promise 对象的 cancel 属性。这样就能够成功地调用 myPromise.cancel() 来取消 Promise

function createCancelablePromise() {
let isCanceled = false;
let cancel;

const promise = new Promise((resolve, reject) => {
// 模拟一个异步操作
const timeoutId = setTimeout(() => {
if (!isCanceled) {
resolve("Promise resolved");
}
}, 5000);

// 中断函数
cancel = function() {
isCanceled = true;
clearTimeout(timeoutId);
reject(new Error("Promise canceled"));
};
});

promise.cancel = cancel;

return promise;
}

const myPromise = createCancelablePromise();

// 在某个条件下中断 Promise
myPromise.cancel();

4.2 Promise 的状态为什么一经变更, 无法改变呢?

Promise 的状态可以通过以下三种方式变更: resolve(): 将 PromisePending状态置为Fulfilled; reject(): 用于将 PromisePending状态置为Rejected; throw(): 用于将 PromisePending 状态置为 Rejected。其中:

  • Promise.prototype.resolve 内部首先检测当前 Promise 状态是否为 Pending, 只有处于 Pending 的状态下, 执行后续 resolve 的逻辑。比如改变 Promise 状态为 Fulfilled, 遍历存储的成功回调数组, 执行每一个回调。

  • Promise.prototype.reject 同理, 内部首先检测当前 Promise 状态是否为 Pending, 只有处于 Pending 的状态下, 执行后续 reject 的逻辑。比如改变 Promise 状态为 Rejected, 遍历存储的失败回调数组, 执行每一个回调。