JavaScript - Promise异步
看过很多关于Promise的文章、但想真正了解和在项目中使用、还是需要自己、撸一次代码才能真的了解使用。
本文从回调地域到常用的异步解决方案逐步了解;
回调地狱
回调地狱 术语通常用来描述
function asyncTask(){
asyncA(function(flag){
if(flag)
{
return run(flag);
}
asyncB(function(flag){
if(flag)
{
return run(flag);
}
...
})
})
}
这样的回调使得,难以维护代码,和管理流程变得困难。
Promise
ES6中Promise
提供了一种异步编程解决方案,比传统的回调函数相比更合理、强大;
- Promise对象是个构造函数,用来生成Promise实例。
- Promise构造函数接受一个函数作为参数,该函数有两个参数
resolve
和reject
。 resolve
函数作用是将当前Promsie对象的状态改为从”未完成”变为”完成”,在异步操作成功时调用,并将返回的接口作为参数传递给resolve
函数,reject
函数作用将当前Promsie对象的状态从”未完成”变为”失败”,在异步操作失败时调用。- Promise实例生成以后,由于Promsie可以链式调用,可以在声明后面添加
then()
方法,方法接受两个参数作为回调函数,第一个参数resolve
成功时,第二个reject
失败时调用函数;
let is = true;
function run()
{
//声明实例
const promise = new Promise((resolve,reject)=>{
if(is)
{
resolve('done'); //成功
}
else
{
reject('fail'); //失败
}
})
.then((a)=>{ //处理结果
console.log(a);
},
(a)=>{
console.log(a);
});
};
run(); //done
可以看出Promise脱离了回调地域,异步任务完成后,通过实例.then()方法,执行相应结果的回调函数
在执行Promise任务时,当代码发生错误时、通常我们可以在最后使用.catch()来做个兜底处理错误作用。
let s = new Promise((done,fail)=>{
throw "error";
});
s.then(done=>{
console.log(done);
},
fail=>{
console.log(fail); //错误 error
})
.catch(msg=>{
console.log(`错误`,msg);
});
但其实并不然,Promise作为链式处理结果,其catch是s.then返回的Promise、而不是s所返回的,实际错误会被then里的回调函数所执行。
catch() 方法返回一个Promise,并且处理拒绝的情况。它的行为与调用
Promise.prototype.then(undefined, onRejected)
相同。 (事实上, 调用obj.catch(onRejected)
内部callsobj.then(undefined, onRejected)
).
引用MDN文档、reject和catch是相同的、其都会调用onRejected。
如果Promise在resolve后面报错、不会被捕获,同时也不会响应回调函数,因为在promise状态确定就无法再改变;
Promise.all
在真实的场景中,我们需要执行的异步可能不只一个可能很多,他们有相应的依赖,如果其中一个出现错误,可能需要通知用户。虽然Promise相比之前回调函数已经非常简洁、但是过多的话、看上去还是有点凌乱、难以理解。
Promise.all方法,当所有参数内的Promise实例执行成功(resolve)时,返回一个Promise(resolve)成功回调,反之如其中一个Promise实例失败(reject),则立即返回Promise(reject)失败回调。
let fetch1 = Promise.resolve(33);
let fetch2 = Promise.resolve(22);
let fetch3 = new Promise(function(resolve, reject) {
setTimeout(() => {
resolve(11);
}, 300);
});
Promise.all([fetch1, fetch2, fetch3]).then(res => {
console.log(res);
})
// [33, 22, 11]
ES7 Async/await
这就是相比Promise更有用的地方、它允许你这样编写异步。
async function asynctask(cb){
const userInfo = await userInfo();
if(!userInfo) return cb('no userInfo found');
const savedTask = await addList(userInfo);
if(savedTask) return cb('add failure');
cb(savedTasks);
}
- Async返回的是个Promsie对象、可以像Promise一样使用then方法执行下一步操作。Async函数 可以看做多个异步操作、包装成的一个Promise对象、await命令就是内部then方法的语法糖。
- await 操作符等于等待一个promise对象。它只能在异步函数async function中使用。所以正常情况下await后面是个promise对象。如果不是、await会把该值转换成已正常处理的promise、返回该值本身;
上面的代码看起是更清晰了,但是、错误处理呢?
由于异步函数在等待Promise、当Promise遇到错误时、它会抛出一个异常、该异常将在Promise的catch方法中捕获。
在async/await函数中,通常使用try/catch块来捕获此类错误。
const fetchData = () => {
return new Promise( (resolve, reject) =>{
settimeout(resolve(),300)
} )
};
async function main() {
try {
const res = await fetchData();
}
catch(e) {
console.log(e);
}
};
延展阅读:
how-to-write-async-await-without-try-catch-blocks-in-javascript