【异步编程】Promise

分手后的思念是犯贱 2023-10-13 17:23 69阅读 0赞

Promise的基本用法

创建promise对象

Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。

Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolve和reject。

  1. const promise = new Promise(function(resolve, reject) {
  2. // ... some code
  3. if (/* 异步操作成功 */){
  4. resolve(value);
  5. } else {
  6. reject(error);
  7. }
  8. });

promise有哪些方法

Promise有五个常用的方法:then()、catch()、all()、race()、finally。

1.then方法

当Promise执行的内容符合成功条件时,调用 resolve 函数,失败就调用reject 函数。那么这里的 resolve 函数在哪定义的呢?其实你传给 then 的函数就是 resolve 函数。

  1. let MyPromise = new Promise(function (resolve, reject) {
  2. setTimeout(function () {
  3. const user = {
  4. id: 1, name: "Codereasy" };
  5. resolve(user);
  6. }, 1000);
  7. });
  8. MyPromise.then(function (param) {
  9. console.log(param);
  10. });

2.catch方法

Promise 对象除了有 then 方法,还有一个 catch 方法。比如,当我们在 Promise 里面抛出异常,调用了 reject 方法,这个 reject 方法是在哪定义的呢?其实你传给 catch 的函数就是这个 reject 方法。

  1. let MyPromise = new Promise(function (resolve, reject) {
  2. setTimeout(function () {
  3. const user = {
  4. id: 1, name: "Codereasy" };
  5. reject("当前出现了网络错误,返回404");
  6. }, 1000);
  7. });
  8. MyPromise.then(function (param) {
  9. console.log(param);
  10. }).catch(function (param) {
  11. console.log("调用了catch方法");
  12. console.log(param);
  13. });

3.all方法

假设我们需要有 3 个异步任务(比如3个异步请求),我们希望在 3 个异步任务全部执行完毕之后,一起把请求结果打印出来,应该如何实现呢?答案是使用 all 方法。

all方法可以完成并行任务, 它接收一个数组,数组的每一项都是一个promise对象。当数组中所有的promise的状态都达到resolved的时候,all方法的状态就会变成resolved,如果有一个状态变成了rejected,那么all方法的状态就会变成rejected。

  1. let promise1 = new Promise((resolve,reject)=>{
  2. setTimeout(()=>{
  3. resolve(1);
  4. },2000)
  5. });
  6. let promise2 = new Promise((resolve,reject)=>{
  7. setTimeout(()=>{
  8. resolve(2);
  9. },1000)
  10. });
  11. let promise3 = new Promise((resolve,reject)=>{
  12. setTimeout(()=>{
  13. resolve(3);
  14. },3000)
  15. });
  16. Promise.all([promise1,promise2,promise3]).then(res=>{
  17. console.log(res);
  18. //结果为:[1,2,3]
  19. })

4.race方法

假设有这么一个场景,我们发送了 3 个请求,我们只需要返回速度最快的请求。比如 2 号请求最先返回,那么我们直接打印 2 号的返回结果,不管 1号和 3号了,那么这种情况下就需要使用 race。

race方法和all一样,接受的参数是一个每项都是 promise 的数组,但是与all不同的是,当最先执行完的事件执行完之后,就直接返回该promise对象的值。如果第一个promise对象状态变成resolved,那自身的状态变成了resolved;反之第一个promise变成rejected,那自身状态就会变成rejected。

  1. let promise1 = new Promise((resolve,reject)=>{
  2. setTimeout(()=>{
  3. reject(1);
  4. },2000)
  5. });
  6. let promise2 = new Promise((resolve,reject)=>{
  7. setTimeout(()=>{
  8. resolve(2);
  9. },1000)
  10. });
  11. let promise3 = new Promise((resolve,reject)=>{
  12. setTimeout(()=>{
  13. resolve(3);
  14. },3000)
  15. });
  16. Promise.race([promise1,promise2,promise3]).then(res=>{
  17. console.log(res);
  18. //结果:2
  19. },rej=>{
  20. console.log(rej)};
  21. )

race和all的区别是什么
(1)Promise.all
Promise.all可以将多个Promise实例包装成一个新的Promise实例。同时,成功和失败的返回值是不同的,成功的时候返回的是一个结果数组,而失败的时候则返回最先被reject失败状态的值。
Promise.all中传入的是数组,返回的也是是数组,并且会将进行映射,传入的promise对象返回的值是按照顺序在数组中排列的,但是注意的是他们执行的顺序并不是按照顺序的,除非可迭代对象为空。
需要注意,Promise.all获得的成功结果的数组里面的数据顺序和Promise.all接收到的数组顺序是一致的,这样当遇到发送多个请求并根据请求顺序获取和使用数据的场景,就可以使用Promise.all来解决。
(2)Promise.race
顾名思义,Promse.race就是赛跑的意思,意思就是说,Promise.race([p1, p2, p3])里面哪个结果获得的快,就返回那个结果,不管结果本身是成功状态还是失败状态。当要做一件事,超过多长时间就不做了,可以用这个方法来解决:

  1. Promise.race([promise1,timeOutPromise(5000)]).then(res=>{
  2. })

5.finally方法

通过之前的例子,我们知道了,当在 Promise 内部调用 resolve 的时候,会执行 then 里面的回调函数,当在 Promise 内部执行 reject 的时候,会执行 catch 里面的回调函数。假设我们有一个函数,不管是 promise 内部调用了 reject 还是 resolve,都希望它能执行,那么就需要使用到 finally 方法。

finally方法用于指定不管 Promise 对象最后状态如何,都会执行的操作。该方法是 ES2018 引入标准的。

  1. let MyPromise = new Promise(function (resolve, reject) {
  2. setTimeout(function () {
  3. const user = {
  4. id: 1, name: "Codereasy" };
  5. reject("当前出现了网络错误,返回404");
  6. }, 1000);
  7. });
  8. MyPromise.then(function (param) {
  9. console.log(param);
  10. })
  11. .catch(function (param) {
  12. console.log("调用了catch方法");
  13. console.log(param);
  14. })
  15. .finally(() => {
  16. console.log("执行了finally方法");
  17. });

Promise解决了什么样的问题

在promise出现之前,如果需要进行异步操作,一般都使用回调函数。但是如果回调函数嵌套层数过多,就会造成回调地狱:

在工作中经常会碰到这样一个需求,比如我使用ajax发一个A请求后,成功后拿到数据,需要把数据传给B请求;那么需要如下编写代码:

  1. let fs = require('fs')
  2. fs.readFile('./a.txt','utf8',function(err,data){
  3. fs.readFile(data,'utf8',function(err,data){
  4. fs.readFile(data,'utf8',function(err,data){
  5. console.log(data)
  6. })
  7. })
  8. })

上面的代码有如下缺点:

后一个请求需要依赖于前一个请求成功后,将数据往下传递,会导致多个ajax请求嵌套的情况,代码不够直观。
如果前后两个请求不需要传递参数的情况下,那么后一个请求也需要前一个请求成功后再执行下一步操作,这种情况下,那么也需要如上编写代码,导致代码不够直观。

Promise出现之后,代码变成这样:

  1. let fs = require('fs')
  2. function read(url){
  3. return new Promise((resolve,reject)=>{
  4. fs.readFile(url,'utf8',function(error,data){
  5. error && reject(error)
  6. resolve(data)
  7. })
  8. })
  9. }
  10. read('./a.txt').then(data=>{
  11. return read(data)
  12. }).then(data=>{
  13. return read(data)
  14. }).then(data=>{
  15. console.log(data)
  16. })

发表评论

表情:
评论列表 (有 0 条评论,69人围观)

还没有评论,来说两句吧...

相关阅读

    相关 异步编程——promise

    异步编程——promise 定义 Promise是异步编程的一个解决方案,相比传统的解决方法——回调函数,使用Promise更为合理和强大,避免了回调函数之间的层层嵌套,...