当前位置: 首页 > ds >正文

Promise简介和使用

文章目录

  • 一、异步和同步编程简介
  • 二、Promise
    • 1.Promise简介
    • 2.特点
    • 3. 基本用法


一、异步和同步编程简介

  1. 同步编程:代码从上到下顺序执行,上面的代码不执行完毕,下面的代码不执行
  2. 异步编程:代码执行的时候,遇见异步代码,不会等待,继续执行下面同步代码,同步代码执行完毕后;再去执行异步代码

    异步操作

    1. 事件
    2. ajax事件
    3. 定时器
  3. 为什么引入同步和异步

    同步
    顺序执行‌:代码按照书写顺序逐行执行,前一个任务完成后,才能执行下一个任务。
    阻塞性‌:如果某个任务耗时较长(如文件读写、网络请求),后续代码必须等待它完成才能继续执行。
    异步
    非阻塞执行‌:任务发起后,程序继续执行后续代码,无需等待耗时操作完成。
    ‌并行处理‌:通过回调(Callbacks)、Promise、事件循环(Event Loop)等机制,在后台处理耗时任务,完成后通知主程序。
    引入同步和异步机制的核心原因
    在于‌平衡执行效率、资源利用率与代码复杂性之间的矛盾‌,以满足不同场景下的系统需求

  4. 异步的弊端
    1. 异步编程获取结果的方式和同步编程不一样,
      同步编程:可以基于函数的返回值获取结果,
      异步编程:需要通过回调函数的方式获取结果。
    2. 基于回调方式去处理异步问题,会出现回调嵌套,一般也叫回调地狱,不利于后期的维护和阅读

二、Promise

Promise解决回调地狱的问题
Promise是原生的对象

1.Promise简介

Promise是ES6提出一种异步解决方案, 比传统的解决方案——回调函数和事件——更合理和更强大。它由社区最早提出和实现,ES6 将其写进了语言标准,统一了用法,原生提供了Promise对象。
Promise 是一个对象,从它可以获取异步操作的消息。Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理。

2.特点

  1. 对象的状态不受外界影响
    Promise 是一个容器对象,保存未来某个异步操作的结果(成功或失败),并通过统一 API 管理这些操作

    ‌Pending(进行中)‌:初始状态,异步操作未完成。
    Fulfilled(已成功)‌:异步操作成功完成,返回结果值。
    ‌Rejected(已失败)‌:异步操作失败,返回错误原因
    状态一旦从 Pending 变为 Fulfilled 或 Rejected,则不可逆

  2. 一旦状态改变,就不会再变,任何时候都可以得到这个结果
    Promise对象的状态改变

    从pending变为fulfilled
    从pending变为rejected
    有了Promise对象,就可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。此外,Promise对象提供统一的接口,使得控制异步操作更加容易。

  3. 缺点

    无法取消Promise,一旦新建会立即执行,无法中途取消。
    如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。
    当处于pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。

3. 基本用法

  1. 创建Promise‌
    通过构造函数传入执行器函数(Executor),内部调用 resolve 或 reject 改变状态
    const promise = new Promise((resolve, reject) => {// 可以同步或者异步代码, 一般写异步代码setTimeout(() => {Math.random() > 0.5 ? resolve("成功") : reject("失败");}, 1000);});
    
  2. 响应结果

    .then():处理成功状态(Fulfilled)的结果。
    .catch():处理失败状态(Rejected)的错误。
    .finally():无论成功或失败均执行清理操作,用于指定不管 Promise 对象最后状态如何,都会执行的操作。该方法是 ES2018 引入标准的。

  3. 链式调用
    const fs = require('fs')function read(path) {return new Promise((resolve, reject) => {fs.readFile(path, 'utf-8', (error, data) => {if (error) {reject(error)} else {resolve(data)}})})
    }
    let ap = read('./a.txt').then((data) => {console.log('a.txt', data);return read('./b.txt')
    }, error => {console.log(error);
    }).then((data) => {console.log('b.txt',data);return read('./c.txt')
    }, error => {console.log(error);
    })
    .then((data) => {console.log('c.txt',data);
    }, error => {console.log(error);
    })
    
    在这里插入图片描述
  4. Promise.all()
    并行执行多个 Promise,全部成功时返回结果数组,任一失败则立即终止
    Promise.all()方法用于将多个 Promise 实例,包装成一个新的 Promise 实例
    const p1 = Promise.resolve(1);
    const p2 = Promise.resolve(2);
    const p3 = Promise.resolve(3);Promise.all([p1, p2, p3]).then(results => console.log(results));
    
    在这里插入图片描述
  • 状态改变:
    1. 全部成功
      仅当所有输入的 Promise 均变为 fulfilled 时,返回的 Promise p 才会变为 fulfilled,且结果按顺序组成数组传递给 .then()
    2. 任一失败
      若任意一个输入的 Promise 变为 rejected,则 p 立即变为 rejected,并将 ‌第一个被拒绝的原因‌ 传递给 .catch()
  • 错误处理机制:

    未捕获的拒绝‌
    若输入的 Promise 未显式定义 .catch() 且被拒绝,Promise.all() 会直接终止执行,后续操作不会触发

    Promise.all([p1, p2.reject(), p3]).finally(() => console.log("不会执行"));
    

    推荐做法
    为每个输入的 Promise 显式处理错误(如 .catch()),避免静默失败

  1. Promise.race()
    返回最先完成的 Promise(无论成功或失败)
    Promise.race()方法同样是将多个 Promise 实例,包装成一个新的 Promise 实例。

    ‌成功优先‌:若第一个完成的 Promise 是 fulfilled,p 会直接成功。
    失败优先‌:若第一个完成的 Promise 是 rejected,p 会直接失败。

    // 失败优先
    const p1 = new Promise(resolve => setTimeout(resolve, 100, "成功1"));
    const p2 = new Promise(reject => setTimeout(reject, 200, "失败2"));
    const p3 = new Promise(reject => setTimeout(reject, 50, "失败3"));Promise.race([p1, p2, p3]).then(result => console.log(result))  // 输出 "失败3"(p3 先完成).catch(error => console.error(error));// 成功优先
    const p4 = new Promise(reject => setTimeout(reject, 150, "失败4"));
    const p5 = new Promise(resolve => setTimeout(resolve, 100, "成功5"));
    const p6 = new Promise(resolve => setTimeout(resolve, 50, "成功6"));
    Promise.race([p4, p5, p6]).then(result => console.log(result)).catch(error => console.error(error));  // 输出 "成功6"(p6 先完成)
    
    在这里插入图片描述
  • 超时控制:异步操作限时执行
    通过 Promise.race() 实现 ‌超时中断逻辑‌,提升程序的健壮性。
    // 模拟异步任务(如 API 请求)
    function asyncTask() {return new Promise(resolve => setTimeout(resolve, 3000, "任务完成"));
    }// 超时控制(2秒内未完成则终止)
    function timeout(ms) {return new Promise((_, reject) => setTimeout(reject, ms, "超时!"));
    }Promise.race([asyncTask(), timeout(2000)]).then(result => console.log(result))  .catch(error => console.error(error));  // 2秒后输出 "超时!"
    
  • 竞速请求:获取最快的响应结果
    从多个数据源(如 CDN 节点)发起并行请求,优先使用最先返回的结果。
    // 模拟不同延迟的 API 请求
    const api1 = fetch("https://api1.example.com").then(res => res.json());
    const api2 = fetch("https://api2.example.com").then(res => res.json());
    const api3 = fetch("https://api3.example.com").then(res => res.json());Promise.race([api1, api2, api3]).then(data => console.log("最快响应:", data)).catch(error => console.error("请求全部失败"));
    
  • 错误隔离:避免竞速中的全局失败
    若需在某个 Promise 失败后仍处理其他结果,需显式捕获单个错误。
    const p1 = new Promise(resolve => setTimeout(resolve, 100, "成功"));
    const p2 = new Promise((_, reject) => setTimeout(reject, 50, "失败"));// 为每个 Promise 添加错误处理
    const safeRace = Promise.race([p1.catch(error => ({ type: "error", error })),p2.catch(error => ({ type: "error", error }))
    ]);safeRace.then(result => {if (result.type === "error") console.error("捕获到错误:", result.error);else console.log("成功结果:", result);
    });
    // 输出 "捕获到错误:失败"(p2 先完成,但错误已被隔离)
    
  • 注意事项

    未完成的 Promise 仍会继续执行(需手动取消或忽略);
    错误需显式处理,避免静默失败;
    结果的顺序与输入顺序无关,仅依赖完成速度。

  1. Promise.allSettled()
    等待所有 Promise 完成,返回包含每个结果状态和值的数组
    等到一组异步操作都结束了,不管每一个操作是成功还是失败,再进行下一步操作在ES2020引入了Promise.allSettled()方法,用来确定一组异步操作是否都结束了(不管成功或失败)
    Promise.allSettled()方法接受一个数组作为参数,数组的每个成员都是一个 Promise 对象,并返回一个新的 Promise 对象。只有等到参数数组的所有 Promise 对象都发生状态变更(不管是fulfilled还是rejected),返回的 Promise 对象才会发生状态变更。
  • 混合成功与失败的 Promise
    无论输入 Promise 是成功(fulfilled)或失败(rejected),Promise.allSettled() 均会等待所有 Promise 完成,并返回一个包含每个结果状态和值的数组
    	const p1 = Promise.resolve("成功1");const p2 = Promise.reject("失败2");const p3 = new Promise(resolve => setTimeout(resolve, 100, "成功3"));Promise.allSettled([p1, p2, p3]).then(results => {results.forEach(result => console.log(result));});/* 输出:{ status: 'fulfilled', value: '成功1' }{ status: 'rejected', reason: '失败2' }{ status: 'fulfilled', value: '成功3' }
    */
    
  • 错误处理场景:统一处理全部结果
    在需要 ‌批量处理异步操作且容忍部分失败‌ 的场景中,Promise.allSettled() 可避免因单个失败中断流程
    // 模拟多个 API 请求(部分可能失败)
    const requests = [fetch("/api/user"),fetch("/api/orders").catch(() => "订单请求失败"),fetch("/invalid-url").catch(error => error.message)
    ];Promise.allSettled(requests).then(results => {results.forEach((result, index) => {if (result.status === "fulfilled") console.log(`请求 ${index + 1} 成功:`, result.value);else console.error(`请求 ${index + 1} 失败:`, result.reason);});});
    
  • 对比 Promise.all():忽略部分失败
    当需要 ‌仅关注成功结果,但允许部分失败‌ 时,可通过 filter 过滤已完成的成功值
    const promises = [Promise.resolve("数据A"),Promise.reject("错误B"),Promise.resolve("数据C")
    ];Promise.allSettled(promises).then(results => {const successfulData = results.filter(result => result.status === "fulfilled").map(result => result.value);console.log("有效数据:", successfulData);  // 输出 ["数据A", "数据C"]});
    
  • 实际应用:批量操作结果统计
    适用于需要汇总异步操作结果的场景,如 ‌批量文件上传、多服务状态检查‌ 等
    // 模拟文件上传(部分成功/失败)
    const uploadTasks = [{ id: 1, task: Promise.resolve("文件1上传成功") },{ id: 2, task: Promise.reject("文件2上传超时") },{ id: 3, task: Promise.resolve("文件3上传成功") }
    ];Promise.allSettled(uploadTasks.map(task => task.task)).then(results => {const successCount = results.filter(r => r.status === "fulfilled").length;const errorCount = results.filter(r => r.status === "rejected").length;console.log(`成功:${successCount},失败:${errorCount}`);  // 输出 "成功:2,失败:1"});
    
  • 注意事项

    结果顺序与输入顺序一致,与完成时间无关68;
    未完成的 Promise 仍会阻塞最终结果返回

  1. Promise.any()
    ES2021 引入了Promise.any()方法。该方法接受一组 Promise 实例作为参数,包装成一个新的 Promise 实例返回。

    Promise.any()跟Promise.race()方法很像,只有一点不同,就是Promise.any()不会因为某个 Promise 变成rejected状态而结束,必须等到所有参数 Promise 变成rejected状态才会结束

  • 返回值类型

    异步兑现‌:只要有一个 Promise 成功,返回的 Promise 即以其值兑现13。
    ‌异步拒绝‌:

    • 所有 Promise 均失败时,返回的 Promise 以 AggregateError 拒绝,其 errors 属性包含所有失败原因。
    • 若传入空的可迭代对象,立即拒绝并抛出 AggregateError
  • 与 Promise.race() 的区别
    Promise.race() 返回第一个解决(无论成功或失败)的 Promise
    Promise.any() 仅关注第一个成功的 Promise,忽略所有拒绝,直到全部失败才抛出错误
    const promises = [Promise.reject('Error 1'),Promise.reject('Error 2'),new Promise((reject) => setTimeout(reject, 100, 'Delayed')),Promise.reject('Error 3'),
    ];Promise.any(promises).then((value) => console.log(value)) .catch((error) => console.error(error.errors)); // [ 'Error 1', 'Error 2', 'Delayed', 'Error 3' ]
    
  1. Promise.resolve()
    有时需要将现有对象转为 Promise 对象,Promise.resolve()方法就起到这个作用
    Promise.resolve()等价于下面的写法
    Promise.resolve('foo')
    // 等价于
    new Promise(resolve => resolve('foo'))
    
    Promise.resolve()方法的参数分成四种情况。
    • 参数是一个 Promise 实例
      如果参数是 Promise 实例,那么Promise.resolve将不做任何修改、原封不动地返回这个实例。
         const p1 = new Promise(resolve => resolve('success'));const p2 = Promise.resolve(p1);console.log(p1 === p2); // 输出 true
      
    • 参数是一个thenable对象
      参数为实现了 then() 方法的对象(thenable),自动转换为 Promise。
      const thenable = {then(resolve) { resolve(42); }
      };
      Promise.resolve(thenable).then(data => console.log(data));
      
    • 参数不是具有then()方法的对象,或根本就不是对象
      如果参数是一个原始值,或者是一个不具有then()方法的对象,则Promise.resolve()方法返回一个新的 Promise 对象,状态为resolved。
      const p = Promise.resolve('Hello');p.then(function (s) {console.log(s)
      });
      // Hello
      
    • 不带有任何参数
      Promise.resolve()方法允许调用时不带参数,直接返回一个resolved状态的 Promise 对象。
      Promise.resolve().then(() => console.log('微任务执行'));
      setTimeout(() => console.log('宏任务执行'), 0);
      // 输出顺序:微任务执行 → 宏任务执行
      
  2. Promise.reject()
    Promise.reject(reason)方法也会返回一个新的 Promise 实例,该实例的状态为rejected。
    Promise.reject()方法的参数,会原封不动地作为reject的理由,变成后续方法的参数。
    const p = Promise.reject('出错了');
    // 等同于
    const p = new Promise((resolve, reject) => reject('出错了'))p.then(null, function (s) {console.log(s)
    });
    // 出错了
    
  3. Promise.try()
    不知道或者不想区分,函数f是同步函数还是异步操作,但是想用 Promise 来处理它。因为这样就可以不管f是否包含异步操作,都用then方法指定下一步流程,用catch方法处理f抛出的错误。
    如果f是同步函数,会在本轮事件循环的末尾执行。
  • 替代立即执行异步函数 替代 (async () => { … })() 写法。
    // 传统写法
    (async () => {try {const data = await fetchData();} catch (err) { /* ... */ }
    })();// Promise.try 写法
    Promise.try(fetchData).then(data => console.log(data)).catch(err => console.error(err));
    
    async () => f()会吃掉f()抛出的错误。所以,如果想捕获错误,要使用promise.catch方法
  • 包装第三方库函数
    将可能抛出同步异常的库函数封装为 Promise 接口。
    // 假设第三方库函数可能同步报错
    const parseJSON = str => JSON.parse(str);
    Promise.try(() => parseJSON('{invalid json}')).catch(err => console.error('JSON解析失败:', err.message)); // 输出错误信息:ml-citation{ref="5" data="citationList"}
    
  • 结合 Promise 链式调用
    在复杂链式调用中统一错误处理入口。
    Promise.try(() => {return getUserSession(); // 可能同步或异步报错
    }).then(session => fetchUserData(session.id)).then(data => renderUI(data)).catch(err => showErrorToast(err.message));:ml-citation{ref="5,8" data="citationList"}
    
  • 处理混合型函数
    兼容返回值、Promise 或抛异常的函数。
    function mixedFunc(flag) {if (flag) return 42; // 同步返回值if (flag === null) return Promise.reject('拒绝'); // 异步拒绝throw new Error('异常'); // 同步报错
    }Promise.try(() => mixedFunc(null)).catch(err => console.error(err)); // 输出 "拒绝":ml-citation{ref="5" data="citationList"}
    
  • ‌核心优势总结‌:
    1. 错误处理统一化‌:同步错误自动转为异步拒绝,避免遗漏未捕获异常58。
    2. 接口规范化‌:强制函数返回 Promise,消除同步/异步代码差异5。
    3. 代码简洁性‌:减少冗余的 try/catch 或 new Promise 封装代码
http://www.xdnf.cn/news/2140.html

相关文章:

  • HDRnet——双边滤波和仿射变换的摇身一变
  • 如何在 MinGW 和 Visual Studio (MSVC) 之间共享 DLL
  • Freertos--统计所有任务栈信息以及CPU占比和钩子函数
  • Flutter Dart 集合类型List Set Map详解军 以及循环语句 forEaclh map where any every
  • 【动手学大模型开发】VSCode 连接远程服务器
  • 苹果iosApp提交审核常见问题--内购订阅篇
  • 技术视界 | 从自然中获取智慧: 仿生机器人如何学会“像动物一样思考和行动”
  • 《算法笔记》4.2小节——算法初步->哈希
  • 【Redis】hash类型
  • 每日c/c++题 备战蓝桥杯(P1252洛谷 马拉松接力赛)
  • 《深入理解 AOP》
  • 数图信息科技邀您共赴第二十五届中国零售业博览会
  • spring中的@bean注解详解
  • Springoot、Flowable快速学习
  • 制作一款打飞机游戏25:添加数据
  • C++与Python编写二进制转十进制
  • 一种双模式机器人辅助股骨干骨折钢板植入方法
  • 【AI平台】n8n入门3:第二个工作流,链接网上大模型(含三种方式)
  • wireshark从HEX转储导入使用方法
  • 数学基础 -- 欧拉恒等式的魅力:让复数旋转起来!
  • MATLAB基础应用精讲-【基础知识篇】发布和共享 MATLAB 代码
  • 网络流量分析 | 流量分析基础
  • 机器学习基础 - 回归模型之线性回归
  • SD2351核心板:重构AI视觉产业价值链的“超级节点”
  • 【高频考点精讲】JavaScript事件循环机制:从宏任务微任务到渲染时机
  • MySQL数据库(13) 用户管理
  • Redis高效赋能机器学习实战:用FastAPI打造智能钓鱼邮件识别与缓存系统全流程解析
  • nacos设置权重进行负载均衡不生效
  • MongoDB 图片 URL 存储异常问题解决方案
  • C++入侵检测与网络攻防之网络嗅探以及ARP攻击