阅读视图

发现新文章,点击刷新页面。

Promise 解决过程(Promise Resolution Procedure)详解

Promise 解决过程是 Promise A+ 规范的核心机制,用于处理 then 回调返回值与 Promise 状态的关系。以下从规范角度结合代码示例解析这一过程。

一、解决过程的核心定义

Promise 解决过程是一个抽象操作 [[Resolve]](promise, x),表示将 promise 的状态与值根据 x 的类型和状态进行解析。其核心逻辑是:x 是 Promise 或 Thenable(具有 then 方法),则使 promise 接受 x 的状态;否则用 x 的值完成 promise

二、解决过程的具体规则

1. xpromise 为同一对象

  • 规则:若 promisex 指向同一实例,以 TypeError 拒绝 promise,避免循环引用。
  • 示例
    const promise = new Promise(resolve => {
      resolve(promise); // promise 和 x 为同一对象
    });
    
    promise.then(
      value => console.log('成功'),
      reason => console.log('错误:', reason) // 输出:错误: TypeError
    );
    

2. x 是 Promise 实例

  • 规则
    • x 处于 pendingpromise 保持 pending,直至 x 状态确定。
    • x 处于 fulfilledpromise 以相同值 fulfilled
    • x 处于 rejectedpromise 以相同原因 rejected
  • 示例
    function createPromise(delay, value) {
      return new Promise(resolve => {
        setTimeout(() => resolve(value), delay);
      });
    }
    
    const p1 = createPromise(100, 'p1 resolved');
    const p2 = new Promise(resolve => {
      resolve(p1); // x 是 Promise
    });
    
    p2.then(
      value => console.log('p2 结果:', value), // 输出:p2 结果: p1 resolved
      reason => console.log('p2 错误:', reason)
    );
    

3. x 是 Object 或 Function(Thenable)

  • 规则
    1. 尝试获取 x.then,若获取时抛出异常 e,则以 e 拒绝 promise
    2. then 是函数,调用 x.then(resolvePromise, rejectPromise),其中:
      • resolvePromise(y):递归执行 [[Resolve]](promise, y)
      • rejectPromise(r):以 r 拒绝 promise
      • resolvePromiserejectPromise 被多次调用,仅首次有效。
    3. 若调用 then 时抛出异常 e,且 resolvePromise/rejectPromise 未被调用,则以 e 拒绝 promise
    4. then 不是函数,以 x 完成 promise
  • 示例
    // 定义 Thenable 对象
    const thenable = {
      then(resolve, reject) {
        console.log('调用 then 方法');
        setTimeout(() => {
          resolve('thenable value'); // 调用 resolvePromise
        }, 500);
      }
    };
    
    const promise = new Promise(resolve => {
      resolve(thenable); // x 是 Thenable
    });
    
    promise.then(
      value => console.log('结果:', value), // 输出:结果: thenable value
      reason => console.log('错误:', reason)
    );
    

4. x 是普通值(非对象、非函数)

  • 规则:以 x 直接完成 promise
  • 示例
    const promise = new Promise(resolve => {
      resolve(42); // x 是普通值
    });
    
    promise.then(
      value => console.log('普通值结果:', value), // 输出:普通值结果: 42
      reason => console.log('错误:', reason)
    );
    

三、解决过程在链式调用中的体现

function promise1() {
  return new Promise(resolve => {
    setTimeout(() => {
      console.log('promise1 完成');
      resolve('p1 value');
    }, 1000);
  });
}

function promise2() {
  return new Promise(resolve => {
    setTimeout(() => {
      console.log('promise2 完成');
      resolve('p2 value');
    }, 2000);
  });
}

// 链式调用中返回 Promise
promise1()
  .then(value => {
    console.log('then1 接收值:', value); // then1 接收值: p1 value
    return promise2(); // x 是 Promise,触发解决过程
  })
  .then(value => {
    console.log('then2 接收值:', value); // then2 接收值: p2 value(等待 promise2 完成)
  })
  .catch(error => {
    console.log('错误:', error);
  });

解决过程解析

  1. promise1 完成后,then1 返回 promise2x 是 Promise)。
  2. [[Resolve]](promise2, x) 执行:
    • promise2 处于 pending,当前 then2 的 Promise 保持 pending
    • promise2 完成时,当前 Promise 以相同值完成,触发 then2 回调。

四、解决过程中的异常处理

const promise = new Promise(resolve => {
  // 模拟 Thenable 中抛出异常
  resolve({
    then: function() {
      throw new Error('Thenable 内部错误');
    }
  });
});

promise.then(
  value => console.log('成功:', value),
  reason => console.log('错误:', reason) // 输出:错误: Thenable 内部错误
);

异常流程

  1. resolve 传入 Thenable 对象。
  2. 获取 x.then 时未出错,但调用 x.then 时抛出异常。
  3. 解决过程捕获异常,以该异常拒绝 promise

五、解决过程的核心意义

  1. 保证状态一致性:无论 x 是普通值、Promise 还是 Thenable,解决过程确保 promise 状态与 x 正确关联。
  2. 支持链式调用:通过递归处理 x,实现 Promise 链的无缝衔接。
  3. 兼容不同实现:使原生 Promise 与第三方 Promise 库(如 Bluebird)可相互操作。

理解 Promise 解决过程是掌握 Promise 异步编程的关键,尤其在处理复杂链式调用和异常场景时,能帮助开发者预测和调试代码行为。

Promise A+ 规范解读

前言

任何符合 promise 规范的对象或函数都可以成为 promise,promise A plus 规范地址:promisesaplus.com/

术语

  • Promise:promise 是一个拥有 then 方法的对象或函数,其行为符合本规范。
  • 具有 then 方法(thenable):是一个定义了 then 方法的对象或函数;
  • 值(value):指任何 JavaScript 的合法值(包括 undefined,thenable 和 promise);
  • 异常(exception):是使用 throw 语句抛出的一个值。
  • 原因(reason):表示一个 promise 的拒绝原因。

promise 的状态

一个 Promise 的当前状态必须为以下三种状态中的一种:等待态(Pending)、已完成(Fulfilled)和已拒绝(Rejected)。

  • 处于等待态时,promise 需满足以下条件:可以变为「已完成」或「已拒绝」
  • 处于已完成时,promise 需满足以下条件:
    • 不能迁移至其他任何状态
    • 必须拥有一个不可变的值
  • 处于已拒绝时,promise 需满足以下条件:
    • 不能迁移至其他任何状态
    • 必须拥有一个不可变的原因

必须有一个 then 方法

一个 promise 必须提供一个 then 方法以访问其当前值和原因。 promise 的 then 方法接受两个参数:promise.then(onFulfilled, onRejected) 他们都是可选参数, 同时他们都是函数,如果 onFulfilled 或 onRejected 不是函数,则需要忽略他们。

  • 如果 onFulfilled 是一个函数
    • 当 promise 执行结束后其必须被调用,其第一个参数为 promise 的值
    • 在 promise 执行结束前其不可被调用
    • 其调用次数不可超过一次
  • 如果 onRejected 是一个函数
    • 当 promise 被拒绝执行后其必须被调用,其第一个参数为 promise 的原因
    • 在 promise 被拒绝执行前其不可被调用
    • 其调用次数不可超过一次

其他规则

  • 在执行上下文堆栈仅包含平台代码之前,不得调用 onFulfilled 或 onRejected
  • onFulfilled 和 onRejected 必须被作为普通函数调用(即非实例化调用,这样函数内部 this 非严格模式下指向 window)
  • then 方法可以被同一个 promise 调用多次
    • 当 promise 成功执行时,所有 onFulfilled 需按照其注册顺序依次回调
    • 当 promise 被拒绝执行时,所有的 onRejected 需按照其注册顺序依次回调
  • then 方法必须返回一个 promise 对象 promise2 = promise1.then(onFulfilled, onRejected);
    • 只要 onFulfilled 或者 onRejected 返回一个值 x,promise 2 都会进入 onFulfilled 状态
    • 如果 onFulfilled 或者 onRejected 抛出一个异常 e,则 promise2 必须拒绝执行,并返回拒因 e
    • 如果 onFulfilled 不是函数且 promise1 状态变为已完成,promise2 必须成功执行并返回相同的值
    • 如果 onRejected 不是函数且 promise1 状态变为已拒绝,promise2 必须执行拒绝回调并返回相同的据因
var promise1 = new Promise((resolve, reject) => {
    reject();
});
const promise2 = promise1
   .then(null, function() {
        return 123
    });

promise2
   .then(
        () => {
            console.log('promise2 已完成');
        },
        () => {
            console.log('promise2 已拒绝');
        }
    );

Promise 基础概念与实践详解

在支持 ES6 的高级浏览器环境中,我们通过 new Promise() 即可构造一个 Promise 实例。这个构造函数接受一个函数作为参数,该函数分别接收两个参数 resolvereject,用于将当前实例的状态改变为 已完成已拒绝

一、Promise 实例与构造函数核心特性

  • 实例方法:Promise 实例可通过 .then 方法注册回调函数,根据实例状态(已完成/已拒绝)执行对应回调。
  • 状态控制:通过 new Promise() 构造函数的回调函数可动态更改实例状态。
  • 本质:Promise 并非新语法,而是一个新函数。
  • 执行机制:Promise 同步注册,异步执行。

二、Promise 链式调用示例

function promise1() {
    return new Promise(function(resolve, reject) {
        // 定义异步操作
        setTimeout(function() {
            console.log('1s 后输出');
            // 执行 resolve 标记为已完成,继续执行 then 链
            resolve();
        }, 1000);
    });
}

function promise2() {
    return new Promise(function(resolve) {
        setTimeout(function() {
            console.log('2s 后输出');
            resolve();
        }, 2000);
    });
}

// 链式调用写法
promise1().then(function() { return promise2(); });
// 简写形式
promise1().then(promise2);

执行结果:1 秒后输出 "1s 后输出",再过 2 秒输出 "2s 后输出"。

核心逻辑:当 Promise 状态变为 已完成(调用 resolve),则执行 .then 中的下一个 Promise 函数;若状态变为 已拒绝(调用 reject),则进入异常处理函数。

三、Promise 状态处理与参数传递

function promise3() {
    return new Promise(function(resolve, reject) {
        const random = Math.random() * 10; // 生成 0-10 的随机数
        setTimeout(function() {
            if (random >= 5) {
                resolve(random); // 状态变为已完成,传递参数
            } else {
                reject(random);  // 状态变为已拒绝,传递参数
            }
        }, 1000);
    });
}

const onResolve = function(val) {
    console.log('已完成: 输出的数字是', val);
};

const onReject = function(val) {
    console.log('已拒绝: 输出的数字是', val);
};

// 方式1:通过 then 接收两个回调
promise3().then(onResolve, onReject);

// 方式2:通过 catch 捕获异常
promise3().catch(onReject).then(onResolve);

// 方式3:通过 try catch 拦截
try {
    promise3().then(onResolve);
} catch (e) {
    onReject(e);
}

关键说明

  • 三种方式可拦截 已拒绝 状态的 Promise:then 的第二个参数、.catch 方法、try catch
  • resolvereject 可传递参数,供后续 .then 回调接收。

四、Promise 核心概念总结

  1. 状态机制

    • Promise 有三种状态:进行中(pending)已完成(fulfilled)已拒绝(rejected)
    • 状态仅能从 pending 转为 fulfilledrejected,且一旦变更不可逆转。
  2. 构造函数

    • ES6 中通过 new Promise(executor) 构造实例,executor 接收 resolvereject 函数。
    • 执行 resolve 使状态变为 fulfilled,执行 reject 使状态变为 rejected
  3. 链式调用

    • 通过 .then 方法在 Promise 状态为 fulfilled 时继续执行后续逻辑。
    • resolve/reject 传递的参数可被后续 .then 回调获取。
  4. 异常处理

    • 已拒绝的 Promise 可通过 .catchthen 的第二个参数或 try catch 捕获处理。
❌