美文网首页
🔑 Promise 核心要点

🔑 Promise 核心要点

作者: 白公子是猫奴 | 来源:发表于2025-11-30 15:34 被阅读0次

理解 Promise 的关键在于把握其状态常用方法

  • 三种状态:Promise 有三种状态,分别是 pending(进行中)fulfilled(已成功)rejected(已失败)。状态一旦改变,就不可逆(从 pending 变为 fulfilled 或 rejected)。
  • 链式调用与错误捕获:Promise 可以链式调用,通过 .then() 方法处理成功情况,通过 .catch() 方法捕获链中发生的任何错误,这使得异步代码更易读,避免了"回调地狱"。
  • 常用静态方法
    • Promise.all([...]):接收一个 Promise 实例的数组。只有当所有 Promise 都成功完成时,它才成功,返回值是所有 Promise 结果组成的数组;如果其中有一个被拒绝,Promise.all 会立即拒绝,并返回第一个失败的原因。
    • Promise.race([...]):同样是接收一个 Promise 数组,但其中任何一个 Promise 完成(无论成功或失败)或拒绝时,它就会随之完成或拒绝,并返回那个最快改变的 Promise 的结果。

💡 RN 中 Promise 的应用场景

在 React Native 中,Promise 常用于以下场景:

  • RN 与原生模块交互:RN 调用原生模块(Native Modules)时,原生端可以通过 Promise 将结果返回给 RN 的 JavaScript 端。这种方式比传统的 Callback 更清晰,也便于处理异步成功或失败。
  • 网络请求:RN 中的 fetch 函数或第三方库(如 axios)广泛使用 Promise 来处理 HTTP 请求。

🧠 Promise 面试题选析

面试中常会考察对 Promise 概念和运行机制的理解,以下是一些典型题目:

1. 基础输出与状态变化

这类问题主要考察对 Promise 状态、链式调用以及事件循环中微任务执行顺序的理解。

  • 题目示例

    console.log(1);
    new Promise((resolve, reject) => {
      console.log(2);
      resolve();
    }).then(() => {
      console.log(3);
    });
    console.log(4);
    

    输出顺序是 1, 2, 4, 3。原因是:new Promise 中的执行器函数是同步执行的,所以先输出 1 和 2。resolve() 后将 .then() 中的回调加入微任务队列,等待同步任务(输出 4)执行完毕后再执行,因此最后输出 3。

  • 错误处理与"穿透"

    Promise.resolve('Success!')
      .then(data => {
        data.toUpperCase() // 注意:这里没有 return
      })
      .then(data => {
        console.log(data) // 输出:undefined
      })
    

    如果 .then() 中的函数没有显式地 return 一个值,后续 .then() 接收到的就是 undefined

2. 手写实现类

这类问题考察对 Promise 原理和用法的深入理解。

  • 实现 Promise.first()
    Promise.first() 并不是 ES 标准方法,其目标是:给定一组 Promise,只要其中第一个成功完成(fulfilled) 的 Promise 出现,就忽略后续的任何拒绝和完成。这与 Promise.race 不同,race 是第一个" settled "(无论成功或失败)的。

    一个简单的实现思路是:用一个数组记录失败的原因,当成功完成的 Promise 数量达到要求或者所有 Promise 都已结束时,决定外层 Promise 是完成还是拒绝。

    Promise.first = function (promises) {
      let rejections = [];
      return new Promise((resolve, reject) => {
        promises.forEach(promise => {
          promise.then(resolve).catch(error => {
            rejections.push(error);
            if (rejections.length === promises.length) {
              reject(new AggregateError(rejections, "All promises were rejected"));
            }
          });
        });
      });
    };
    
  • 实现顺序执行
    给你一个包含多个异步操作(返回 Promise)的数组,如何让它们顺序执行,即一个完成后才开始下一个?

    function order(promises) {
      let result = [];
      let sequence = Promise.resolve();
      for (let promise of promises) {
        sequence = sequence.then(() => promise).then(data => result.push(data));
      }
      return sequence.then(() => result);
    }
    

    核心思路是:构建一个 Promise 链,每个环节都在上一个完成后执行当前 Promise。需要注意的是,这种方式虽然保证了执行顺序,但数组中的 Promise 在传入时可能已经开始,若要真正"串行"发起,需在链中动态创建 Promise。

      // 推荐写法(函数数组 + for/await)
      async function runInOrder(tasks: (() => Promise<any>)[]) {
          const results = [];
          for (const task of tasks) {
          results.push(await task());
      }
      return results;
      }
      
      const task1 = () => new Promise(resolve => setTimeout(() => resolve('任务1完成'), 1000));
      const task2 = () => new Promise(resolve => setTimeout(() => resolve('任务2完成'), 500));
      const task3 = () => new Promise(resolve => setTimeout(() => resolve('任务3完成'), 200));
    
      runInOrder([task1, task2, task3]).then(results => {
      console.log(results); // ['任务1完成', '任务2完成', '任务3完成']
      });
    

    传入的是返回 Promise 的函数数组,每个异步操作只有在前一个完成后才开始,真正实现串行。

3. 并发控制

有时需要控制并发请求的数量,例如有 8 个图片 URL 要请求,但要求同时最多 3 个请求。

一种思路是:初始化一个"执行池",当池中有空位且还有剩余任务时,就取出一个新任务执行。任务完成后再从池中移除,并尝试添加新任务。

// 限制并发数的异步加载
function limitLoad(urls, limit) {
  let executing = 0;
  let index = 0;
  const results = [];

  function run(url) {
    if (index >= urls.length) return Promise.resolve();
    
    executing++;
    return loadImg(url) // 你的异步函数,返回 Promise
      .then(result => {
        results.push(result);
        executing--;
        if (index < urls.length) {
          return run(urls[index++]);
        }
      });
  }

  const initialPromises = [];
  for (let i = 0; i < limit && i < urls.length; i++, index++) {
    initialPromises.push(run(urls[i]));
  }
  return Promise.allSettled(initialPromises).then(() => results);
}

最佳实践建议使用 async/await + Promise.all + 控制池的方式,代码更易维护和理解。如下:

  const results: any[] = [];
  let i = 0;

  // 工作池
  const pool: Promise<void>[] = [];

  // 启动 limit 个并发任务
  const enqueue = async () => {
    while (i < urls.length) {
      const currentIndex = i++; // 为了避免异步任务里用到的索引被后续循环修改,确保每个任务的索引唯一且正确。
      const p = loadImg(urls[currentIndex])
        .then(res => {
          results[currentIndex] = res; // 保证结果顺序
        });
      pool.push(p);

      // 控制并发数
      if (pool.length >= limit) {
        await Promise.race(pool);
        // 移除已完成的任务
        pool.splice(pool.findIndex(promise => promise === p), 1);
      }
    }
  };

  await enqueue(); // 等待所有任务都被加入 pool,开始执行
  await Promise.all(pool); // 等待剩余任务完成
  return results;
}

✅ 面试准备建议

  1. 理解概念:务必理解 Promise 的状态链式调用错误冒泡/捕获.catch)以及静态方法 allraceallSettledany 的区别。
  2. 熟悉事件循环:明白 Promise 的回调属于微任务,以及它们与宏任务(如 setTimeout)的执行优先级。
  3. 动手练习:多写代码,尝试手写 Promise 的简单实现、allrace 等方法,以及处理各种异步流程控制。
  4. 结合 RN 场景思考:思考在 RN 开发中,哪些地方用到了 Promise,比如网络请求 fetch、与原生模块的通信、异步存储等,理解其在实际项目中的应用。

相关文章

  • 什么是Promise,它到底解决了什么问题?

    什么是Promise Promise 是异步编程的一种解决方案 Promise 核心 Promise 概括来说是对...

  • Promise要点记录

    1.什么是Promise?Promise是抽象异步处理对象以及对其进行各种操作的组件。2.三种类型Construc...

  • 手写promise

    1. promise核心 使用 promise加入异步逻辑 前面的promise没有加异步的情况。增加异步就是在t...

  • Promise实现链式调用

    上一篇文章实现了Promise最基础功能,本文将实现promise核心的链式调用

  • 深度剖析:手写一个Promise源码

    目录 一、Promise核心逻辑实现 二、在 Promise 类中加入异步逻辑 三、实现 then 方法多次调用添...

  • 理解Promise in JavaScript

    Promise是JavaScript中的一个核心概念,初学JavaScript,对Promise的概念和用法都比较...

  • promise函数详解

    复制到你的vscode上看//promise最核心的思想:用同步的流程解决异步的操作 //Promise 构造函数...

  • 2021-12-27

    1.Promise核心知识点1)一个 Promise 必然处于以下几种状态之一 ?:待定 (pending): 初...

  • 手写Promise核心代码

    https://www.bilibili.com/video/BV1RR4y1p7my?spm_id_from=3...

  • Angular $q

    $q采用的是promise式的异步编程.什么是promise异步编程呢?异步编程最重要的核心就是回调,因为有回调函...

网友评论

      本文标题:🔑 Promise 核心要点

      本文链接:https://www.haomeiwen.com/subject/pdcvqstx.html