什么是:专门保证多个异步函数,可以顺序执行的机制。而且防止了回调地狱的问题。
ES6 promise
第一步:异步函数的内部,用 new Promise(function(door){…})包裹原函数中所有的代码。
第二步:在异步任务执行完最后一步后,调用附赠的开关door()开门,通知下一项任务可以执行;
第三步:将整个new Promise()对象返回到函数内部,再使用.then()接下一项任务函数。
function fn1(){
return new Promise(
function(door){
var demo="唯一的一个接力棒";
console.log(`1号拿着${demo}起跑。。。`);
setTimeout(function(){
console.log(`1号拿着${demo}到达终点`);
console.log(`1号打开了门(door),把${demo}交给了下一位`);
door(demo);
}, 3000);
}
)
}
function fn2(demo){
return new Promise(
function(door){
console.log(`2号拿着${demo}起跑。。。`);
setTimeout(() => {
console.log(`2号到达了终点`);
console.log(`2号打开了门,把${demo}交给了下一位`);
door(demo);
}, 2000);
}
)
}
function fn3(demo){
return new Promise(
function(door){
console.log(`3号拿着${demo}起跑`);
setTimeout(() => {
console.log(`3号到达终点`);
console.log(`3号打开了门`);
door();
}, 5000);
}
)
}
执行
fn1().then(fn2).then(fn3).then(()=>console.log("比赛结束了"))
当前一个函数内调用door()后,就等于通知了.then()中的下一个函数可以开始执行。于是.then()就自动执行下一个函数。
注意:
1 then()中的下一个异步函数后不要加(),因外下一个异步函数不是立即调用,而是等前一个函数开门。
2 .then()能否接下一个.then(),取决于前一个.then()中的函数是否也支持promise。如果前一个.then()中的函数支持promise,则.then()可以继续.then()。否则不能继续.then().(???)
如何实现前后两个函数之间的传参:
(1)上一个函数中有door;
(2)下一个函数(最外层函数)定义时就要定义一个形参用来接。
原理:参数值会顺着.then()交给.then()中的下一个函数的形参变量。下一个就可以通过自己的形参变量获取到上一步传过来的参数值。
局限:door()只能传递一个变量。如果传递多个值,可以将多个值放在数组或者对象中整体传入。
错误处理
当异步执行任务发生错误,就可以从报错的门(.catch())出去。且一旦从报错这扇门出去,后续的.then()都不再执行。
function fn1(){
return new Promise(
function(door,err){
var demo="唯一的一个接力棒";
console.log(`1号拿着${demo}起跑。。。`);
setTimeout(function(){
if(Math.random()>0.5){
console.log(`1号拿着${demo}到达终点`);
console.log(`1号打开了门(door),把${demo}交给了下一位`);
door(demo);
}else{
console.log(`1号摔倒了`);
err("1号摔倒了");
}
}, 3000);
}
)
}
function fn2(demo){
return new Promise(
function(door,err){
console.log(`2号拿着${demo}起跑。。。`);
setTimeout(() => {
if (Math.random()<=0.5){
console.log(`2号到达了终点`);
console.log(`2号打开了门,把${demo}交给了下一位`);
door(demo);
}else{
console.log(`2号摔倒了`);
err("2号摔倒了");
}
}, 2000);
}
)
}
function fn3(demo){
return new Promise(
function(door,err){
console.log(`3号拿着${demo}起跑`);
setTimeout(() => {
if (Math.random()>0.5){
console.log(`3号到达终点`);
console.log(`3号打开了门`);
door();
}else{
console.log("3号摔倒了");
err("3号摔倒了")
}
}, 5000);
}
)
}
//调用:
fn1().then(fn2).then(fn3).then(()=>console.log("比赛结束了"))
.catch(function(err){
console.log(err);
console.log("弃权!")
})
**.catch()**方法用来捕捉按顺序执行的出错的异步程序,其中某一步出错,后面的异步程序都不再执行。
promise的问题:没有彻底消除嵌套。
当多个异步函数需要顺序执行时:
(async function(){
同步代码;
var 返回值=await 异步函数;
同步代码;
} )()
具体代码如下:
(async function(){
try{
var bang=await fn1();
bang=await fn2(bang);
await fn3(bang);
console.log("比赛结束");
}catch(err){
console.log(err);
console.log("有人摔倒,比赛结束");
}
})();
promise深入理解
await: 让整段匿名函数自调暂时挂起,等待当前异步函数执行结束,再执行后续代码
注意:
1 ES7的async和await仅仅简化的是promise函数调用的部分。并没有简化promise函数的定义。且如果想用await,则异步函数必须定义为支持promise的样式;
2 如果await修饰的异步函数中调用了err()方法,打开了错误的门,则await会认为程序错误。此时应该使用try{}catch(err){} 解决;
3 只有async下的try catch 才能捕获异步任务中的错误。没在async下的js基础所学的try catch 是无法捕捉异步任务的。因为js基础中的try catch 属于主程序,不会等到异步任务执行,就已经结束了。即使异步任务出错,try catch因为早就结束了,所以无法捕获到。
4 为何await 配合try catch就可以捕获异步任务中的错误?
答:因为await能留住当前程序中的一切代码,等待异步函数执行结束。try catch就有可能捕获到异步任务中的错误。