IT评测·应用市场-qidao123.com

标题: Promise的九大方法(resolve、reject、then、catch、finally、all、allSettl [打印本页]

作者: 宁睿    时间: 2024-6-9 15:01
标题: Promise的九大方法(resolve、reject、then、catch、finally、all、allSettl
媒介:
          定期复盘---今天我们来复习一下 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 状态




1. Promise.resolve

    静态方法 Promise.resolve(value)可以认为是 new Promise方法的语法糖,比如Promise.resolve(42) 可以认为是以下代码的语法糖。
  1. new Promise(function (resolve) {
  2.     resolve(42)
  3. })
复制代码
     这个静态方法会让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("romise reject error")) 就是下面代码的语法糖形式
  1. new Promise(function (reject) {
  2.     reject(new Error("Promise reject error"))
  3. })
复制代码
      简单总结一下 Promise.reject方法的话:它的功能是调用该 Promise对象通过then指定的 onRejected函数,并讲错误(Error)对象通报给这个onRejected函数


3. Promise.then

    Promise.then(onFulfilled, onRejected)
  ① 函调函数异步执行

  1. var promise = new Promise((resolve, reject) => {
  2.   console.log("inner Promise"); // 1
  3.   setTimeout(() => {
  4.     resolve("Fashion Barry"); // 3
  5.   }, 1000);
  6. });
  7. promise.then((res) => {
  8.   console.log("res", res);
  9. });
  10. console.log("outer promise"); // 2
  11. // Promise 实际是一个同步函数,then 方法才是异步
  12. // 所以输出顺序如上
复制代码
  Promise/A+规范统一规定:Promise 只能使用异步调用方式

  ② 返回值   

    不管你在回调函数 onFulfilled中会返回一个什么样的值,大概不返回值,该值都会由 Promis.resolve(return 的返回值) 进行响应的包装处理。因此,最终 then的结果都是返回一个新创建的 Promise对象。
    也就是说,Promis.then不仅仅是注册一个回调函数那么简单,它还会将回调函数的返回值进行变换,创建并返回一个Promise 对象。正是 then函数中有了如许返回值的机制,才能使得在整个Promise链式结构当中,每个then方法都能给 下一个then方法通报参数。现在我们知道怎么返回的Promise是之前的还是新的?另外该Promise的状态又是怎样?
  1. var aPromise = new Promise((resolve, reject) => {
  2.   resolve("aPromise");
  3. });
  4. var thenPromise = aPromise.then((res) => {
  5.   console.log("thenPromise: ", res);
  6. });
  7. var catchPromise = aPromise.catch((err) => {
  8.   console.error("catchPromise: ", err);
  9. });
  10. console.log(aPromise !== thenPromise); // true
  11. console.log(thenPromise !== catchPromise); // true
  12. console.log(aPromise, thenPromise, catchPromise); // Promise { "aPromise" }, Promise { <pending> }, Promise { <pending> }
复制代码
    从上面结果来看,实际上不管是调用 then还是catch方法, 都返回了一个新的Promise对象

  ③ promise穿透

   我们先来举个例子:
  1. Promise.resolve("Barry")
  2. .then(Promise.resolve("Barry Promise"))
  3. .then((result) => {
  4.   console.log("result", result); // "Barry"
  5. });
复制代码
如果你认为输出的是【 Barry Promise 】,那么你就错了,实际上他输出的是 【 Barry 】
产生这么的输出是因为你给then方法通报了一个非函数(比如promise对象)的值,代码会如许明白 : then(null),因此导致了前一个promise的结果产生了坠落的效果,也就是和下面代码是一样的, 代码直接穿透了then(null)进入了下一层链:
  1. Promise.resolve("Barry")
  2. .then(null)
  3. .then((result) => {
  4.   console.log("result", result); // "Barry"
  5. });
复制代码
随意添加多个then(null)结果都是一样的
  1. Promise.resolve("Barry")
  2. .then(null)
  3. .then({ name: "My name is Barry" })
  4. .then(null)
  5. .then((result) => {
  6.   console.log("result", result); // "Barry"
  7. });
复制代码

4. Promise.catch


  ① 语法糖的本质

        这里我们再说一遍,实际上Promise.catch只是promise.then(undefined, onRejected) 方法的一个别名而已。也就是说,这个方法用来注册当Promise对象状态变为 Rejected时 的回调函数。可以看下面代码,两者写法是等价的,但是很显着 Promise.catch会让人第一眼看上去不会眼花缭乱:
  1. // 第一种写法
  2. Promise.resolve()
  3.   .then((data) => console.log(data))
  4.   .then(undefined, (err) => console.log(err));
  5. // 第二种写法
  6. Promise.resolve()
  7.   .then((data) => console.log(data))
  8.   .catch((err) => console.log(err));
复制代码
那么我们现在来说说为什么保举使用第二种方法,而不是第一种:

  ② 只有一个主人

        我们上面已经说过了,在书写很长的Promise链式,从代码清晰度和浅易程度来讲,在末了添加 catch是远远在每一层链上写onRejected回调函数是要好的,因为catch可以捕获 Promise链中每一层节点的错误,这句话本身没有错,但从这句话延伸出一种错误的明白:catch 同时监控着所有节点。实际上catch函数在同一个时间点只属于某一个Promise,因为它的主人是随着程序 的执行而不停变化的,我们来举个例子:
  1. let p1 = new Promise((resolve, reject) => {
  2.   // 第一层执行逻辑
  3.   resolve("first promise"); // Promise(1)
  4. })
  5.   .then((res) => {
  6.     // 第二层执行逻辑
  7.     return "second promise"; // Promise(2)
  8.   })
  9.   .then((res) => {
  10.     // 第三层执行逻辑
  11.     return "third promise"; // Promise(3)
  12.   })
  13.   .catch((err) => {
  14.     console.log("err", err);
  15.   });
复制代码
在上述例子中,如果整个程序每一步都正确执行,那么会次序产生三个Promise对象,分别是 Promise(1),Promise(2),Promise(3):

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


5. Promise.finally

    promise.finally方法的回调函数不接受任何参数,这意味着finally没有办法 知道,前面的Promise状态到底是fulfilled还是rejected 。这表明,finally方法里面的操纵,应该是与Promise状态无关的,不依赖于 Promise的执行结果。我们来看下面代码:
  1. var p1 = new Promise((resolve, rejevt) => {
  2.   setTimeout(() => {
  3.     resolve;
  4.   }, 1000);
  5. });
  6. p1.then((res) => console.log(res))
  7.   .catch((err) => console.log(err))
  8.   .finally(() => console.log("finally"));
复制代码
finally本质上是then方法的特例。我们来看下面伪代码:
  1. promise.finally(() => {
  2.   // 执行逻辑
  3. });
  4. // 上面代码等同于下面
  5. promise.then(
  6.   (onFulilled) => {
  7.     // 语句
  8.     return onFulilled;
  9.   },
  10.   (onRejected) => {
  11.     // 语句
  12.     throw onRejected;
  13.   }
  14. );
复制代码
上面代码中,如果不使用finally方法,同样的语句必要为成功和失败的状态各写一次。 有了finally方法,则只必要写一次。那么它是怎样实现的呢?
  1. Promise.prototype.finally = function (callback) {
  2.   let p = this.constructor;
  3.   return this.then(
  4.     (value) => p.resolve(callback()).then(() => value),
  5.     (reason) =>
  6.       p.reject(callback()).then(() => {
  7.         throw reason;
  8.       })
  9.   );
  10. };
  11. var p = new Promise((resoleve, reject) => {
  12.   setTimeout(() => {
  13.     reject("Promise err");
  14.   }, 1000);
  15. });
  16. p.catch((err) => console.log("err", err)).finally(() => {
  17.   console.log("finally");
  18. });
复制代码
上述代码中,不管前面的Promise是fulfilled还是rejected ,都会执行回调函数callback



6. Promise.all

    Promise.all接受一个promise对象的数组作为参数,当这个数组里的所有 Promise 对象 全部变为resolve大概reject状态的时候,它才会去调用.then方法。
    通报给Promise.all的 promise并不是一个个的次序执行的,而是同时开始、并行执行的,我们可以看下面例子
  1. var promise1 = new Promise((resoleve, reject) => {
  2.   setTimeout(() => {
  3.     resoleve("promise1--3000");
  4.   }, 3000);
  5. });
  6. var promise2 = new Promise((resoleve, reject) => {
  7.   setTimeout(() => {
  8.     resoleve("promise2--1000");
  9.   }, 1000);
  10. });
  11. var promise3 = new Promise((resoleve, reject) => {
  12.   setTimeout(() => {
  13.     resoleve("promise3--5000");
  14.   }, 5000);
  15. });
  16. var promiseArr = [promise1, promise2, promise3];
  17. console.time("promiseArr");
  18. Promise.all(promiseArr)
  19.   .then((res) => {
  20.     console.log("res", res); // ['promise1--3000', 'promise1--1000', 'promise1--5000']
  21.     console.timeEnd("promiseArr"); // 5523.29296875 ms
  22.   })
  23.   .catch((err) => console.log(err));
复制代码
为什么这个例子可以看出来Promise.all()是并行的呢?因为所有Promise执行完只用了5秒,如果3个 Promise是按照次序执行的,那么应该是9秒大概,在5-9之间,因为4个Promise并不是同时执行的,同时执行的 话总时间就是那个花费时间最长的Promise
Promise.all()紧张细节点 (口试常考):



7. Promise.allSettled

  Promise.allSettled()的入参和Promise.all、Promise.race一样,接受一个promise 对象的数组作为参数,也是同时开始、并行执行的。但是Promise.allSettled的返回值必要注意以下几点:
Promise.allSettled不会走进catch,当所有输入Promise都被推行大概拒绝时, statusesPromise 会剖析一个具有具体完成状态的数组

我们看下面示例:
  1. var promise1 = new Promise((resoleve, reject) => {
  2.   setTimeout(() => {
  3.     reject(new Error("promise1--3000"));
  4.     // resoleve("promise1--3000");
  5.   }, 3000);
  6. });
  7. var promise2 = new Promise((resoleve, reject) => {
  8.   setTimeout(() => {
  9.     // reject(new Error("promise1--1000"))
  10.     resoleve("promise2--1000");
  11.   }, 1000);
  12. });
  13. var promise3 = new Promise((resoleve, reject) => {
  14.   setTimeout(() => {
  15.     resoleve("promise3--5000");
  16.     // reject(new Error("promise1--5000"))
  17.   }, 5000);
  18. });
  19. var promiseArr = [promise1, promise2, promise3];
  20. console.time("promiseArr");
  21. Promise.allSettled(promiseArr)
  22.   .then((res) => {
  23.     console.log("res", res);
  24.     console.timeEnd("promiseArr");
  25.   })
  26.   .catch((err) => console.error(err))
  27.   .finally(() => console.log("finally"));
复制代码
总结一下:Promise.allSettled()在你必要执行平行和独立的异步操纵并网络所有结果时非常有效, 即使某些异步操纵可能失败。


8. Promise.race

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

下面我们来举个例子:
  1. let arr = [1000, 3000, 5000, 7000];
  2. let promiseArr = [];
  3. for (let i = 0; i < arr.length; i++) {
  4.   let newPromise = new Promise((resolve, reject) => {
  5.     if (i === 0) {
  6.       reject(new Error("第二个错误"));
  7.     } else {
  8.       setTimeout(() => {
  9.         console.log(arr[i]);
  10.         resolve(arr[i]);
  11.       }, arr[i]);
  12.     }
  13.   });
  14.   promiseArr.push(newPromise);
  15. }
  16. Promise.race(promiseArr)
  17.   .then((res) => {
  18.     console.log(res);
  19.   })
  20.   .catch((err) => {
  21.     console.log(err);
  22.   });
  23. // 控制台报错
  24. // 3000
  25. // 5000
  26. // 7000
复制代码
这里我们再复习一下Node当中变乱循环的知识:



9. Promise.any


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

  1. var promise1 = new Promise((resoleve, reject) => {
  2.   setTimeout(() => {
  3.     // reject(new Error("promise1--3000"));
  4.     resoleve("promise1--3000");
  5.   }, 3000);
  6. });
  7. var promise2 = new Promise((resoleve, reject) => {
  8.   setTimeout(() => {
  9.     // reject(new Error("promise2--1000"))
  10.     resoleve("promise1--1000");
  11.   }, 1000);
  12. });
  13. var promise3 = new Promise((resoleve, reject) => {
  14.   setTimeout(() => {
  15.     // resoleve("promise3--5000");
  16.     reject(new Error("promise1--5000"))
  17.   }, 5000);
  18. });
  19. var promiseArr = [promise1, promise2, promise3];
  20. console.time("promiseArr");
  21. Promise.any(promiseArr)
  22.   .then((res) => {
  23.     console.log("res", res); // res promise1--1000
  24.     console.timeEnd("promiseArr");
  25.   })
  26.   .catch((err) => console.error(err));
  27.   //所有的Promise都失败, AggregateError: All promises were rejected
复制代码
总计一下Promisea.any的应用场景:如果我们现在有多台服务器,则只管使用响应速度最快的服务器,在这种情况下, 可以使用Promise.any()方法从最快的服务器接收响应。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 IT评测·应用市场-qidao123.com (https://dis.qidao123.com/) Powered by Discuz! X3.4