一、什么是Promise
Promise是抽象异步处理对象以及对其进行各种操作的组件。Promise本身是同步的立即执行函数解决异步回调的问题, 当调用 resolve 或 reject 回调函数进行处理的时候, 是异步操作, 会先执行.then/catch等,当主栈完成后,才会去调用执行resolve/reject中存放的方法。
promise的功能是可以将复杂的异步处理轻松地进行模式化。采用Promise,连续读取多个文件,可以解决回调地狱。
如果说到基于JavaScript的异步处理,我想大多数都会想到利用回调函数。
const promise = new Promise(function(resolve, reject) {
// ... some code
if (/* 异步操作成功 */){
resolve(value);
} else {
reject(error);
}
});
Promise则是把类似的异步处理对象和处理规则进行规范化, 并按照采用统一的接口来编写,而采取规定方法之外的写法都会出错。
// 使用Promise进行异步处理的一个例子
var promise = getAsyncPromise("fileA.txt");
promise.then(function(result){
// then 获取文件内容成功时的处理
}).catch(function(error){
// catch 获取文件内容失败时的处理
});
Promise本身是同步的立即执行函数, 当在executor中执行resolve或者reject的时候, 此时是异步操作, 会先执行then/catch等,当主栈完成后,才会去调用resolve/reject中存放的方法执行。
console.log('script start')
let promise1 = new Promise(function (resolve) {
console.log('promise1')
resolve()
console.log('promise1 end')
}).then(function () {
console.log('promise2')
})
setTimeout(function(){
console.log('settimeout')
})
console.log('script end')
// 输出顺序: script start->promise1->promise1 end->script end->promise2->settimeout
二、ES6 Promises 的API方法
1、参数:Promise构造函数接受一个函数作为参数,其中该参数又接受两个函数作为它自身的参数,分别是resolve和reject。
new Promise((resolve, reject) => {
//异步操作
})
promise.then(function(data) {
console.log('success');
}).catch(function(error) {
console.log('error');
});
1.1 resolve
返回一个promise对象成功的状态,并通知给then方法或catch方法,接下来根据对象的状态决定走哪条路,然后执行后续操作;resolve方法的作用是把promise对象的状态从进行中变成已完成,同时可以向resolve方法传入参数,这个参数会在将来被promise对象的then方法获取;
1.2 reject
返回一个失败的promise对象;reject方法也是同样的道理,只不过是把promise对象状态变成失败,同时传入的参数会被catch方法获取而已。
当resolve或reject修改promise对象状态之后,通过检测promise对象的状态,决定执行then还是catch回调方法。在这个过程中:resolve和reject起到的作用是修改对象状态、通知回调函数以及传递回调函数可能需要的参数。这样做的好处就是:把逻辑判断和回调函数分开处理。
2、回调函数 .then 和 .catch
回调函数的调用是根据对象的状态来完成的:进行中、已完成和失败(pending(待定)、fullfilled(成功)、rejected(失败))
2.1 Promise.then
1. 得到异步任务的正确结果;
2. 只有Promsie内部的状态落定了,then方法中对应的处理程序才会执行。
3. then方法的强大之处,可以链式调用
2.2 Promise.catch
进行捕获和处理失败结果
3、方法 .all() 和 .race()
3.1 Promise.all()
- 并发处理多个异步任务(等待机制),所有结果都返回之后,统一打印;
- 谁跑得慢,以谁为准执行回调;
- Promise.all 接收一个 promise对象的数组作为参数,当这个数组里的所有promise对象全部变为resolve或reject状态的时候,它才会去调用
.then
方法。
let wake=(time)=>{
return new Promise(function (resolve,reject){
setTimeout(()=>{
resolve(`${time/1000}秒后醒来`);
},time);
});
}
let p1=wake(10000);
let p2=wake(1000);
Promise.all([p1,p2]).then(res=>{
let [res1,res2]=res;
console.log(res1,res2);
}).catch(err=>{
console.log(err);
})
// 执行结果:10秒后醒来 1秒后醒来
3.2 Promise.race()
- 并发处理多个异步任务(赛跑机制), 任何一个异步操作完成,就执行下一步的.then;请求图片的时候使用;
- 谁跑得快,以谁为准执行回调
let p1=new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve('success');
}, 10000);
});
let p2=new Promise((resolve,reject)=>{
setTimeout(()=>{
reject('faild');
}, 500);
});
Promise.race([p1,p2]).then(res=>{
console.log(res);
}).catch(err=>{
console.log(err); // 返回的是faild
})
三、什么是 async/await
async/await 是简化 Promise 异步操作(语法糖):async 函数返回一个 Promise 对象,当函数执行的时候,一旦遇到 await 就会先返回,等到触发的异步操作完成,再执行函数体内后面的语句。可以理解为,是让出了线程,跳出了 async 函数体
async 函数返回一个 Promise 对象,当函数执行的时候,一旦遇到 await 就会先返回,等到触发的异步操作完成,再执行函数体内后面的语句。可以理解为,是让出了线程,跳出了 async 函数体。
async function async1(){
console.log('async1 start');
await async2();
console.log('async1 end')
}
async function async2(){
console.log('async2')
}
console.log('script start');
async1();
console.log('script end')
// 输出顺序:script start->async1 start->async2->script end->async1 end
1、async 语法
- 自动将常规函数转换成Promise,返回值也是一个Promise对象
- 只有async函数内部的异步操作执行完,才会执行then方法指定的回调函数
- 异步函数内部可以使用await
2、await 语法
1.await 放置在Promise调用之前,await 强制后面点代码等待,直到Promise对象resolve,得到resolve的值作为await表达式的运算结果
2.await只能在async函数内部使用,用在普通函数里就会报错
3、错误处理
在async函数里,无论是Promise reject的数据还是逻辑报错,都会被默默吞掉,所以最好把await放入try{}catch{}中,catch能够捕捉到Promise对象rejected的数据或者抛出的异常
function timeout(ms) {
return new Promise((resolve, reject) => {
setTimeout(() => {reject('error')}, ms); //reject模拟出错,返回error
});
}
async function asyncPrint(ms) {
try {
console.log('start');
await timeout(ms); //这里返回了错误
console.log('end'); //所以这句代码不会被执行了
} catch(err) {
console.log(err); //这里捕捉到错误error
}
}
asyncPrint(1000);
// 执行结果: start
error