【异步编程】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)
})
还没有评论,来说两句吧...