首页IT科技promise 异步编程(Promise的九大方法(resolve、reject、then、catch、finally、all、allSettled、race、any)你都用过那些?)

promise 异步编程(Promise的九大方法(resolve、reject、then、catch、finally、all、allSettled、race、any)你都用过那些?)

时间2025-09-19 12:10:27分类IT科技浏览6643
导读:前言:...

前言:

        定期复盘---今天我们来复习一下 Promise 的几个方法                ,分别是:Promise.resolve                 、Promise.reject                          、Promise.then        、Promise.catch            、Promise.finally                          、Promise.all            、Promise.allSettled        、Promise.race                          、Promise.any;

        接下来我们一起去看看吧                         ,从深处去了解他们有什么区别!!!

目录

Promise 状态

1. Promise.resolve

2. Promise.reject

3. Promise.then

  ① 函调函数异步执行

  ② 返回值   

  ③ promise穿透

4. Promise.catch

  ① 语法糖的本质

  ② 只有一个主人

5. Promise.finally

6. Promise.all

7. Promise.allSettled

8. Promise.race

9. Promise.any

Promise 状态

初始状态 -> pending 初始状态可以改变 在resolve 或者 reject 调用之前都处于这个状态 最终成功状态 -> fulfilled 执行 resolve 函数          ,状态改变为 fulfilled 执行 onFulfilled 函数 最终失败状态 -> rejected 执行 reject 函数            ,状态改变为 rejected 执行 onRejected 函数 then 方法 then 方法为 Promise 对象注册了 onFulfilled 和 onRejected 函数 catch 方法 catch 方法为Promise 对象注册了 onRejected 函数

1. Promise.resolve

    静态方法Promise.resolve(value)可以认为是new Promise方法的语法糖,比如Promise.resolve(42)可以认为是以下代码的语法糖                 。

new Promise(function (resolve) { resolve(42) })

     这个静态方法会让Promise对象立即进入确定(即resolved) 状态                        ,并将42传递给后面 then 里所指定的 onFulfilled函数                          。作为new Promise的快捷方式              ,在进行 Promise对象的初始化或者编写测试代码的时候都非常方便        。

      简单总结一下 Promise.resolve方法的话        ,它的作用就是将传递给它的参数填充 Fulfilled到 Promise对象后并返回这个Promise对象            。

2. Promise.reject

  Promise.reject(error)是和Promise.resolve(value)类似的静态方法                        ,是new Promise方法的快捷方式                          。比如Promise.reject(new Error("Promise reject error"))就是下面代码的语法糖形式

new Promise(function (reject) { reject(new Error("Promise reject error")) })

      简单总结一下 Promise.reject方法的话:它的功能是调用该Promise对象通过then指定的onRejected函数                  ,并讲错误(Error)对象传递给这个onRejected函数

3. Promise.then

    Promise.then(onFulfilled, onRejected)

  ① 函调函数异步执行

var promise = new Promise((resolve, reject) => { console.log("inner Promise"); // 1 setTimeout(() => { resolve("Fashion Barry"); // 3 }, 1000); }); promise.then((res) => { console.log("res", res); }); console.log("outer promise"); // 2 // Promise 实际是一个同步函数    ,then 方法才是异步 // 所以输出顺序如上

  Promise/A+规范统一规定:Promise 只能使用异步调用方式

  ② 返回值   

    不管你在回调函数 onFulfilled中会返回一个什么样的值                        ,或者不返回值                      ,该值都会由Promis.resolve(return 的返回值)进行响应的包装处理            。因此,最终then的结果都是返回一个新创建的Promise对象        。

    也就是说                    ,Promis.then不仅仅是注册一个回调函数那么简单                          ,它还会将回调函数的返回值进行变换     ,创建并返回一个Promise对象                          。正是then函数中有了这样返回值的机制                ,才能使得在整个Promise链式结构当中                         ,每个then方法都能给 下一个then方法传递参数                。现在我们知道怎么返回的Promise是之前的还是新的?另外该Promise的状态又是如何?

var aPromise = new Promise((resolve, reject) => { resolve("aPromise"); }); var thenPromise = aPromise.then((res) => { console.log("thenPromise: ", res); }); var catchPromise = aPromise.catch((err) => { console.error("catchPromise: ", err); }); console.log(aPromise !== thenPromise); // true console.log(thenPromise !== catchPromise); // true console.log(aPromise, thenPromise, catchPromise); // Promise { "aPromise" }, Promise { <pending> }, Promise { <pending> }

    从上面结果来看          ,实际上不管是调用 then还是catch方法            , 都返回了一个新的Promise对象

  ③ promise穿透

我们先来举个例子:

Promise.resolve("Barry") .then(Promise.resolve("Barry Promise")) .then((result) => { console.log("result", result); // "Barry" });

如果你认为输出的是【 Barry Promise 】                        ,那么你就错了              ,实际上他输出的是 【 Barry 】

产生这么的输出是因为你给then方法传递了一个非函数(比如promise对象)的值        ,代码会这样理解 :then(null),因此导致了前一个promise的结果产生了坠落的效果                        ,也就是和下面代码是一样的                  , 代码直接穿透了then(null)进入了下一层链:

Promise.resolve("Barry") .then(null) .then((result) => { console.log("result", result); // "Barry" });

随意添加多个then(null)结果都是一样的

Promise.resolve("Barry") .then(null) .then({ name: "My name is Barry" }) .then(null) .then((result) => { console.log("result", result); // "Barry" });

4. Promise.catch

  ① 语法糖的本质

        这里我们再说一遍    ,实际上Promise.catch只是promise.then(undefined, onRejected)方法的一个别名而已    。也就是说                        ,这个方法用来注册当Promise对象状态变为 Rejected时 的回调函数                          。可以看下面代码                      ,两者写法是等价的,但是很明显 Promise.catch会让人第一眼看上去不会眼花缭乱:

// 第一种写法 Promise.resolve() .then((data) => console.log(data)) .then(undefined, (err) => console.log(err)); // 第二种写法 Promise.resolve() .then((data) => console.log(data)) .catch((err) => console.log(err));

那么我们现在来说说为什么推荐使用第二种方法                    ,而不是第一种:

使用promise.then(onFulfilled, onRejected)的话                          ,在onFulfilled中发生异常的话     ,onRejected中是捕获不到这个异常的                    。而且如果链式很长                ,每一条链上都要这么写。 在promise.then(onFulfilled).catch(onRejected)的情况下.then中产生异常能在.catch中捕获                      。.then.catch本质上是没有区别的                         , 需要分场合使用

  ② 只有一个主人

        我们上面已经说过了          ,在书写很长的Promise链式            ,从代码清晰度和简易程度来讲                        ,在最后添加 catch是远远在每一层链上写onRejected回调函数是要好的              ,因为catch可以捕获 Promise链中每一层节点的错误        ,这句话本身没有错                        ,但从这句话延伸出一种错误的理解:catch同时监控着所有节点                         。实际上catch函数在同一个时间点只属于某一个Promise                  ,因为它的主人是随着程序 的执行而不断变化的    ,我们来举个例子:

let p1 = new Promise((resolve, reject) => { // 第一层执行逻辑 resolve("first promise"); // Promise(1) }) .then((res) => { // 第二层执行逻辑 return "second promise"; // Promise(2) }) .then((res) => { // 第三层执行逻辑 return "third promise"; // Promise(3) }) .catch((err) => { console.log("err", err); });

在上述例子中                        ,如果整个程序每一步都正确执行                      ,那么会顺序产生三个Promise对象,分别是 Promise(1),Promise(2),Promise(3):

可是如果在第一层具体执行逻辑出错了后                    ,那实际上后面的两个then中的回调函数压根不会被异步执行                          ,所以会直接异步触发catch中的回调函数执行     , 所以这种情况下catchPromise(1)对象的catch    。 如果第一层具体执行逻辑正确执行                ,就会异步触发第二个then中的回调函数执行                         ,那么同理          ,在第二次具体执行逻辑抛出错误            ,会导致Promise(2)的状态变化                        ,所以这种情况下catchPromise(2)对象的catch                 。 同理Promise(3)也是如此

总结下来就是:整个Promise链中              ,catch只属于异步触发它当中回调函数 执行的那个Promise        ,并不属于所有 Promise

5. Promise.finally

    promise.finally方法的回调函数不接受任何参数                        ,这意味着finally没有办法 知道                  ,前面的Promise状态到底是fulfilled还是rejected                          。这表明    ,finally方法里面的操作                        ,应该是与Promise状态无关的                      ,不依赖于 Promise的执行结果        。我们来看下面代码:

var p1 = new Promise((resolve, rejevt) => { setTimeout(() => { resolve; }, 1000); }); p1.then((res) => console.log(res)) .catch((err) => console.log(err)) .finally(() => console.log("finally"));

finally本质上是then方法的特例            。我们来看下面伪代码:

promise.finally(() => { // 执行逻辑 }); // 上面代码等同于下面 promise.then( (onFulilled) => { // 语句 return onFulilled; }, (onRejected) => { // 语句 throw onRejected; } );

上面代码中,如果不使用finally方法                    ,同样的语句需要为成功和失败的状态各写一次                          。 有了finally方法                          ,则只需要写一次            。那么它是如何实现的呢?

Promise.prototype.finally = function (callback) { let p = this.constructor; return this.then( (value) => p.resolve(callback()).then(() => value), (reason) => p.reject(callback()).then(() => { throw reason; }) ); }; var p = new Promise((resoleve, reject) => { setTimeout(() => { reject("Promise err"); }, 1000); }); p.catch((err) => console.log("err", err)).finally(() => { console.log("finally"); });

上述代码中     ,不管前面的Promisefulfilled还是rejected                ,都会执行回调函数callback

6. Promise.all

    Promise.all接受一个promise对象的数组作为参数                         ,当这个数组里的所有 Promise对象 全部变为resolve或者reject状态的时候          ,它才会去调用.then方法        。

传递给Promise.all的 promise并不是一个个的顺序执行的            ,而是同时开始                、并行执行的                        ,我们可以看下面例子

var promise1 = new Promise((resoleve, reject) => { setTimeout(() => { resoleve("promise1--3000"); }, 3000); }); var promise2 = new Promise((resoleve, reject) => { setTimeout(() => { resoleve("promise2--1000"); }, 1000); }); var promise3 = new Promise((resoleve, reject) => { setTimeout(() => { resoleve("promise3--5000"); }, 5000); }); var promiseArr = [promise1, promise2, promise3]; console.time("promiseArr"); Promise.all(promiseArr) .then((res) => { console.log("res", res); // [promise1--3000, promise1--1000, promise1--5000] console.timeEnd("promiseArr"); // 5523.29296875 ms }) .catch((err) => console.log(err));

为什么这个例子可以看出来Promise.all()是并行的呢?因为所有Promise执行完只用了5秒              ,如果3个 Promise是按照顺序执行的        ,那么应该是9秒或者                        ,在5-9之间                  ,因为4个Promise并不是同时执行的    ,同时执行的 话总时间就是那个花费时间最长的Promise

Promise.all()重要细节点 (面试常考):

如果所有的Promise中只有一个执行错误                        ,那么整个Promise.all不会走Promise.all().then()而是走Promise.all().catch()这个流程了                          。但是要注意的是虽然走到了Promise.all().catch()这个流程                       ,但是其他 Promise 还是会正常执行,但不会返回结果 要注意Promise.all()的返回值顺序                    ,Promise.all().then()的返回值顺序和传入的顺序是一致的                          ,笔试时 遇到手写Promise.all()时要注意                。

7. Promise.allSettled

  Promise.allSettled()的入参和Promise.all    、Promise.race一样     ,接受一个promise对象的数组作为参数,也是同时开始                          、并行执行的    。但是Promise.allSettled的返回值需要注意以下几点:

Promise.allSettled不会走进catch                ,当所有输入Promise都被履行或者拒绝时                         , statusesPromise 会解析一个具有具体完成状态的数组

{ status: fulfilled, value:value } :如果相应的promise被履行 { status: rejected, reason: reason }:如果相应的promise被拒绝

我们看下面示例:

var promise1 = new Promise((resoleve, reject) => { setTimeout(() => { reject(new Error("promise1--3000")); // resoleve("promise1--3000"); }, 3000); }); var promise2 = new Promise((resoleve, reject) => { setTimeout(() => { // reject(new Error("promise1--1000")) resoleve("promise2--1000"); }, 1000); }); var promise3 = new Promise((resoleve, reject) => { setTimeout(() => { resoleve("promise3--5000"); // reject(new Error("promise1--5000")) }, 5000); }); var promiseArr = [promise1, promise2, promise3]; console.time("promiseArr"); Promise.allSettled(promiseArr) .then((res) => { console.log("res", res); console.timeEnd("promiseArr"); }) .catch((err) => console.error(err)) .finally(() => console.log("finally"));

总结一下:Promise.allSettled()在你需要执行平行和独立的异步操作并收集所有结果时非常有效          , 即使某些异步操作可能失败                          。

8. Promise.race

  Promise.rece()的使用方法和Promise.all一样            ,接收一个promise对象的数组为参数                        ,Promise.race是要有一个promise对象进入Fulfilled或者 Rejected状态的话              ,就会继续进行后面的处理                    。这里依旧有两个点要注意:

Promise.all一样是所有数组当中的Promise同时并行的 Promise.race在第一个Promise对象变为Fulfilled之后        ,并不会 取消其他promise对象的执行。 Promise.race接受的是一个Promise对象数组                        ,但是返回的确实最先完成Fulfilled或者最先被Rejected的一个Promise的结果

下面我们来举个例子:

let arr = [1000, 3000, 5000, 7000]; let promiseArr = []; for (let i = 0; i < arr.length; i++) { let newPromise = new Promise((resolve, reject) => { if (i === 0) { reject(new Error("第二个错误")); } else { setTimeout(() => { console.log(arr[i]); resolve(arr[i]); }, arr[i]); } }); promiseArr.push(newPromise); } Promise.race(promiseArr) .then((res) => { console.log(res); }) .catch((err) => { console.log(err); }); // 控制台报错 // 3000 // 5000 // 7000

这里我们再复习一下Node当中事件循环的知识:

第一层循环:i为0时                  ,异步触发了Promise.race().catch()    ,这里面的回调代码被放在了微任务队列中                        , 后面的3个setTimeout宏任务的回调函数代码被放进了timer阶段中的队列当中(其实并不是这样                      ,因为 三个定时器都有延迟,都是在后面的事件循环中添加进来的) 第二层循环:清空微任务对列                    ,所以控制台打印出了错误                          ,然后清空宏任务     ,分别打印出3000/5000/7000

9. Promise.any

  Promise.any的入参和Promise.all                    、Promise.race、Promise.allSettled一样                , 接收一个promise对象的数组作为参数                      。

只要其中有一个Promise成功执行                         ,就会返回已经成功执行的Promise的结果 如果这个promise对象的数组中没有一个promise可以成功执行(即所有的 promise都失败 )          ,就返回一个失败的promiseAggregateError类型的实例            ,它是Error的一个子类                        ,用于把单一的错误集合 在一起 var promise1 = new Promise((resoleve, reject) => { setTimeout(() => { // reject(new Error("promise1--3000")); resoleve("promise1--3000"); }, 3000); }); var promise2 = new Promise((resoleve, reject) => { setTimeout(() => { // reject(new Error("promise2--1000")) resoleve("promise1--1000"); }, 1000); }); var promise3 = new Promise((resoleve, reject) => { setTimeout(() => { // resoleve("promise3--5000"); reject(new Error("promise1--5000")) }, 5000); }); var promiseArr = [promise1, promise2, promise3]; console.time("promiseArr"); Promise.any(promiseArr) .then((res) => { console.log("res", res); // res promise1--1000 console.timeEnd("promiseArr"); }) .catch((err) => console.error(err)); //所有的Promise都失败              , AggregateError: All promises were rejected

总计一下Promisea.any的应用场景:如果我们现在有多台服务器        ,则尽量使用响应速度最快的服务器                        ,在这种情况下                  , 可以使用Promise.any()方法从最快的服务器接收响应                         。

创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!

展开全文READ MORE
opengl颜色混合出现彩色条纹(Windows OpenGL ES 图像单色)