【异步编程】Promise

Promise的基本用法

创建promise对象

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

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

const promise = new Promise(function(resolve, reject) {
  // ... some code
  if (/* 异步操作成功 */){
    resolve(value);
  } else {
    reject(error);
  }
});

promise有哪些方法

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

1.then方法

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


let MyPromise = new Promise(function (resolve, reject) {
  setTimeout(function () {
    const user = { id: 1, name: "Codereasy" };
    resolve(user);
  }, 1000);
});

MyPromise.then(function (param) {
  console.log(param);
});

2.catch方法

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

let MyPromise = new Promise(function (resolve, reject) {
  setTimeout(function () {
    const user = { id: 1, name: "Codereasy" };
    reject("当前出现了网络错误,返回404");
  }, 1000);
});

MyPromise.then(function (param) {
  console.log(param);
}).catch(function (param) {
  console.log("调用了catch方法");
  console.log(param);
});

3.all方法

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

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

let promise1 = new Promise((resolve,reject)=>{
	setTimeout(()=>{
       resolve(1);
	},2000)
});
let promise2 = new Promise((resolve,reject)=>{
	setTimeout(()=>{
       resolve(2);
	},1000)
});
let promise3 = new Promise((resolve,reject)=>{
	setTimeout(()=>{
       resolve(3);
	},3000)
});
Promise.all([promise1,promise2,promise3]).then(res=>{
    console.log(res);
    //结果为:[1,2,3] 
})

4.race方法

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

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

let promise1 = new Promise((resolve,reject)=>{
	setTimeout(()=>{
       reject(1);
	},2000)
});
let promise2 = new Promise((resolve,reject)=>{
	setTimeout(()=>{
       resolve(2);
	},1000)
});
let promise3 = new Promise((resolve,reject)=>{
	setTimeout(()=>{
       resolve(3);
	},3000)
});
Promise.race([promise1,promise2,promise3]).then(res=>{
	console.log(res);
	//结果:2
},rej=>{
    console.log(rej)};
)

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])里面哪个结果获得的快,就返回那个结果,不管结果本身是成功状态还是失败状态。当要做一件事,超过多长时间就不做了,可以用这个方法来解决:

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

5.finally方法

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

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

 let MyPromise = new Promise(function (resolve, reject) {
   setTimeout(function () {
     const user = { id: 1, name: "Codereasy" };
     reject("当前出现了网络错误,返回404");
   }, 1000);
 });

 MyPromise.then(function (param) {
   console.log(param);
 })
   .catch(function (param) {
     console.log("调用了catch方法");
     console.log(param);
   })
   .finally(() => {
     console.log("执行了finally方法");
   });

Promise解决了什么样的问题

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

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

let fs = require('fs')
fs.readFile('./a.txt','utf8',function(err,data){
  fs.readFile(data,'utf8',function(err,data){
    fs.readFile(data,'utf8',function(err,data){
      console.log(data)
    })
  })
})

上面的代码有如下缺点:

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

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

let fs = require('fs')
function read(url){
  return new Promise((resolve,reject)=>{
    fs.readFile(url,'utf8',function(error,data){
      error && reject(error)
      resolve(data)
    })
  })
}
read('./a.txt').then(data=>{
  return read(data) 
}).then(data=>{
  return read(data)  
}).then(data=>{
  console.log(data)
})

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

codereasy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值