在js中深入分析promise的内部实现原理及常见问题
发布日期:2021-05-08 01:28:07 浏览次数:18 分类:精选文章

本文共 3757 字,大约阅读时间需要 12 分钟。

Promise的内部实现原理

Promise是JavaScript异步编程的一种革命性解决方案,相较于传统的回调函数和事件,它更为合理和强大,目前已被ES6纳入规范,成为JavaScript异步操作的基本单位。以下从实现细节、thenable对象、异步执行机制、状态管理、构造函数以及常见问题等方面进行全面阐述。

thenable对象

thenable对象是Promise实现的核心扩展机制。它定义了一个具有then方法的对象或函数,其目的是提升Promise的通用性。通过thenable,规范化的Promise实现可以与非规范化的实现良好协同工作。类型检查(鸭式辩型)是识别thenable或行为类似Promise对象的主要方式,即根据是否存在then方法来判断。

then回调异步执行

Promise的then方法允许在异步操作完成后注册回调函数。这些回调函数在then方法被调用时,会被异步执行。具体实现机制包括:

  • 立即执行传入的函数:在Promise实例化时,传入的函数会立即执行。
  • 异步延迟调用:then方法中的回调函数需要在事件循环队列中进行延迟执行。
  • 执行环境控制:onFulfilled和onRejected方法仅在事件循环堆栈仅包含平台代码时才能被调用。
  • 任务队列管理:微任务(micro-task)和宏任务(macro-task)的队列管理机制确保回调函数按正确顺序异步执行。
  • Promise状态

    Promise的状态分为三种:等待态(Pending)、执行态(Fulfilled)和拒绝态(Rejected)。一旦Promise被resolve或reject后,状态将保持不变且不可改变。fulfilled和resolved是同义词,onFulfilled和onResolved也是等价的。

    Promise构造函数

    Promise构造函数的主要职责包括:

  • 初始化Promise的状态为等待态。
  • 提供then方法注册回调的接口。
  • 立即执行传入的函数,并传递内部的resolve和reject函数作为参数。
  • 处理多次调用then方法的场景,采用_deferreds数组存储处理对象。
  • then函数

    then方法是Promise链式调用的核心,具体功能包括:

  • 返回新的Promise实例以支持链式调用。
  • 接受可选的onResolved和onRejected参数。
  • 处理当前Promise状态,根据状态决定是否执行回调。
  • 将回调函数和新生成的Promise对象封装存储。
  • 链式调用返回新Promise

    为了支持链式调用,then方法必须返回新的Promise实例。返回的Promise状态将根据当前Promise的状态决定。为了确保链式调用的正确性,then方法需要返回一个能够独立执行的Promise实例。

    resolve函数

    resolve函数是Promise异步处理的核心逻辑。其主要职责包括:

  • 执行传入的函数,获取最终结果。
  • 根据结果判断Promise的状态。
  • 处理thenable对象的情况,遵循Promise Resolution Procedure规范。
  • 处理异常情况,确保异常不会丢失且能够被捕获处理。
  • reject函数

    reject函数的职责是处理异步操作失败的情况,主要包括:

  • 调用拒绝回调。
  • 传递错误信息。
  • 保持Promise的状态不变。
  • handleResolved函数

    handleResolved函数用于处理then方法中的回调函数,特别是在回调函数为空的情况下。它的主要功能包括:

  • 维护链式调用,处理空回调函数。
  • 实现值穿透机制。
  • 返回新的Promise实例以支持进一步的链式调用。
  • then注册回调异步执行

    为了保证回调函数的异步执行,then方法需要确保onFulfilled和onRejected方法在事件循环队列中正确执行。这通常涉及将回调函数添加到微任务队列中。

    Promise内部错误或异常

    Promise在处理异步操作时可能出现错误或异常,包括:

  • Promise被拒绝时,调用拒绝回调并传递错误信息。
  • 异步操作完成后,在处理结果时出现异常,这种情况不会改变Promise的状态,但可能导致新的Promise被拒绝。
  • 使用catch方法进行异常捕获,以确保异步操作的可靠性。
  • Promise的常见问题

    创建Promise的流程

    创建Promise的基本步骤包括:

  • 使用new Promise(fn)Promise.resolve()Promise.reject()创建Promise实例。
  • 在fn函数中定义异步处理逻辑,调用resolve或reject。
  • reject和catch的区别

  • promise.then(onFulfilled, onRejected)中,onFulfilled中的异常无法被onRejected捕获。
  • 使用promise.then(onFulfilled).catch(onRejected).then()可以捕获前面的异常。
  • 建议使用第二种方法,因为它能够捕获所有异常。
  • .catch方法本质上等同于.then(null, onRejected)
  • 异步回调中的异常处理

  • 在then中抛出错误且未处理的情况下,Promise会保持拒绝状态直到错误被捕获。
  • 异步回调中的错误无法被同步回调函数捕获。
  • Promise状态一旦确定,无法再改变。
  • Promise的综合理解

    Promise的实例实现

    从实际场景来看,Promise可以被理解为一个执行多个任务的保姆。以下是一个具体的示例:

    // 买菜的任务
    function buyVegetables() {
    var p1 = new Promise(function(resolve, reject) {
    setTimeout(function() {
    resolve(["鸡蛋", "西红柿", "辣椒"]);
    }, 3000);
    });
    return p1;
    }
    // 做饭的任务
    function cookDinner() {
    var p2 = new Promise(function(resolve, reject) {
    setTimeout(function() {
    resolve({ food: "米饭", greens: "西红柿炒蛋" });
    }, 3000);
    });
    return p2;
    }
    // 送饭的任务
    function mealDelivery() {
    var p3 = new Promise(function(resolve, reject) {
    setTimeout(function() {
    resolve("饭做好了,开始去送饭了");
    }, 3000);
    });
    return p3;
    }
    // 打电话通知的任务
    function inform() {
    var p4 = new Promise(function(resolve, reject) {
    console.log("饭已经送到了,可以吃饭了");
    });
    return p4;
    }
    // 告诉保姆任务的执行
    buyVegetables().then(function(data) {
    console.log(data);
    return cookDinner();
    }).then(function(data) {
    console.log(data);
    return mealDelivery();
    }).then(function(data) {
    console.log(data);
    return inform();
    });

    Promise的总结

    创建Promise的流程包括:

  • 使用new Promise(fn)Promise.resolve(fn)创建Promise实例。
  • 在fn中定义异步操作逻辑,并调用resolve或reject。
  • 在then方法中注册回调函数。
  • 使用catch方法处理异步操作中的异常。
  • Promise的事件循环

    Promise的事件循环机制包括:

  • Promise初始化时,传入的函数立即执行。
  • then方法注册的回调函数会被加入到微任务队列中,按顺序异步执行。
  • 同步代码在事件循环中被执行,确保回调函数的正确执行顺序。
  • Promise的升级

    随着ES6的推出,generator和async/await语法的引入,使得异步处理更加接近同步代码写法,代码可读性更高。async/await本质上是基于Promise实现的,进一步提升了JavaScript的异步编程能力。

    通过以上内容可以看出,Promise作为JavaScript异步编程的核心,极大地简化了异步操作的复杂性,提高了代码的可读性和可维护性。

    上一篇:对于js函数的柯里化深入分析
    下一篇:关于js中对于Promise的深入理解

    发表评论

    最新留言

    路过,博主的博客真漂亮。。
    [***.116.15.85]2025年03月30日 13时30分01秒