利用ES6中Promise的用法及 ES7中的async await解决异步函数顺序执行的回调地狱问题
2020-04-20 19:31
946 查看
Promise
1.什么是promise
promise是专门保证多个异步函数,可以顺序执行的机制。而且还防止了回调地狱问题。
2.何时需要使用promise
多个异步调用的函数,要求必须顺序执行.
3.为什么要使用promise
其实用回调函数,也可以实现多个异步函数,顺序执行。但是,使用回调函数,会有回调地狱问题!
需求:多个异步函数需要按顺序执行
-----错误的解决: 仅按顺序调用
---- 结果: 无法保证顺序执行
----因为: 多个异步函数,每个人一条路,互相之间不会等待。
传统的解决: 使用回调函数:
/*1. 在定义函数时,定义一个callback形参变量 在函数内部,最后一句话执行之后,自动调用callback()*/ function zz(callback){//异步! console.log("开始"); setTimeout(function(){//异步! console.log("结束") //等最后一句话执行完,自动调用提前托付的任务callback callback(); },4000) } /*2. 在调用函数时,传入一个函数,函数中包含下一步要执行的操作。——提前托付*/ zz( //callback function(){ console.log("比赛结束!") } //当zz最后一句话执行完,自动执行callback(),从而完成连续调用 ) //当需要进行连续的异步函数调用时,进行多次callback调用,当重复调用的函数多了便会形成回调地狱
解决方法:使用es6中的promise
前提: 不要用回调函数参数了! 因为回调函数嵌套传参的写法是造成回调地狱的根源 第一步: 在异步函数内部,用new Promise(function(door){ ... })来包裹原函数中所有代码。 其中door是用来打开通向下一项任务的大门的钥匙。 第二步: 在异步任务执行完最后一步之后,调用附赠的开关door(),开门,通知下一项任务可以开始执行。 问题: 不能在函数内写死.then(下一个函数),应该让当前函数可以和之后任意函数自由组合。 第三步: 将整个new Promise()对象返回到函数外部,再用.then()接下一项任务函数 调用支持promise的函数: 前一个异步函数().then(下一个异步函数) 强调: .then()中"下一个异步函数"后不要加(),因为下一个异步函数不是立刻调用,而是在这里等待前一个函数开门。 信任: 前一个函数内调用door()后,就等于通知了.then()中的下一个函数可以开始执行。于是.then()就自动执行下一个函数。 多个异步函数顺序执行: .then()能否接下一个.then(),取决于前一个.then()中的函数是否也支持promise。如果前一个.then()中的函数支持promise,则.then()可以继续.then()。如果前一个.then()中的函数不支持promise,则不能继续.then() 前后两个函数间传参: 2步: 1. 上一个函数中door(参数值) 2. 下一个函数定义时就要定义一个形参准备接 原理: 当上一个函数调用door(参数值)时,参数值,会顺着.then()交给.then()中的下一个函数的形参变量。在下一个中就可通过自己的形参变量获得上一步传下来的参数值。 局限: door()中只能传一个变量 如果必须穿多个值,则可以将多个值放在数组或对象中整体传入。 错误处理: 如何: 任何一个支持promise的函数中都有另一扇门。如果当前异步任务执行过程中发生错误,就可从另一扇门出来。一旦从报错这扇门出来后,后续.then()都不再执行。 其实new Promise()除了then外,还有另一个方法.catch()。凡是从出错的门出来的代码都进入.catch()中执行错误处理操作(无论前面有多少,catch只用写一次)。
function a(){ //1. 用new Promise将整段代码包裹起来 //3. 将整个new Promise对象抛出到函数外部 return new Promise( function(door,err){ var bang="a的接力棒"; console.log(`a拿着${bang} 起跑...`); setTimeout(function(){ if(Math.random()<0.6){ console.log(`a拿着${bang} 到达终点!`); //2. 在异步函数最后一句话执行完,开门通知下一个人可以开始执行。 console.log(`a开门!把${bang}交给下一个人`) door(bang); }else{ console.log(`呀!a摔倒了!!!`); err("a摔倒了"); } },6000) } ) } function b(bang){ //1. 用new Promise()包括原函数所有代码 //3. 将new Promise对象返回到函数外部 return new Promise( function(door,err){ console.log(`b 拿着${bang} 起跑...`); setTimeout(function(){ if(Math.random()<0.6){ console.log(`b 拿着${bang} 到达终点!`); //2. 在当前异步任务结束后,自动调用开关door()开门通知下一个函数可以开始执行 console.log(`b开门!把${bang}交给下一个人`) door(bang) }else{ console.log(`呀!b摔倒了!!!`); err("b摔倒了"); } },2000) } ) } function c(bang){ //1. 用new Promise()包裹原函数左右代码 //3. 返回new Promise()对象到函数外部 return new Promise( function(door){ console.log(`c 拿着${bang} 起跑...`); setTimeout(function(){//异步! console.log(`c 拿着${bang} 到达终点!`) //2. 当c的最后一步任务执行完,自动开门,通知下一个函数可以开始执行 console.log("c开门!") door(); },4000) } ) } a() .then(b) .then(c) .then(()=>console.log("比赛结束")) .catch(function(err){ console.log(err); console.log("弃权!") }) /* a() //2件事: //1. 执行a的任务内容: a起跑... //2. 创建new Promise对象并返回 //return new Promise() .then(ran) //能否继续接.then()取决于ran是否支持new Promise() //当a()中调用door()时,.then()中的ran()开始自动执行! //也干了2件事: //1. 调用b中的任务内容: b起跑... //2. 返回新的new Promise()对象 //return new Promise() .then(c) //c是否可接.then()取决于c内部是否返回new Promise()对象 //当b()中调用door()开门时,c()的内容开始执行: //2件事: //1. 执行c()的函数任务: c起跑.. //2. 返回新的new Promise()对象 //正是因为dong()返回了新的new Promise对象,才可接下一个.then(函数) //return new Promise() .then(function(){ console.log("比赛结束"); }) */
等待多个异步任务完成才执行(同时进行): Promise.all([ 多个支持promise的函数调用(), ..., ..., ]).then(function(){ 后续操作...}) 问题:如果每个异步任务都返回一个接力棒,则如何获得所有接力棒呢? 解决: .then(function(arr){ ... }) 其中: arr数组中保存了Promise.all中所有异步函数通过door()返回的执行结果。 强调: arr中返回值存储的顺序和异步函数执行完成的顺序无关。只和调用的顺序有关!
function a(){ return new Promise( function(door){ var a="a的接力棒"; console.log(`a起跑...`); setTimeout(function(){ console.log(`a到达终点!`); console.log(`a开门`) door(bang); },6000) } ) } function b(){ return new Promise( function(door){ var bang="b的接力棒"; console.log(`b起跑...`); setTimeout(function(){ console.log(`b到达终点!`); console.log(`b开门!`) door(bang) },2000) } ) } function c(){ return new Promise( function(door){ var bang="c的接力棒"; console.log(`c起跑...`); setTimeout(function(){ console.log(`c到达终点!`) console.log("c开门!") door(bang); },4000) } ) } Promise.all([//数组中要求必须传入new Promise对象 a(),//new Promise对象 b(),//new Promise对象 c()//new Promise对象 ]) .then(arr=>{ console.log("比赛结束"); console.log(`收到以下接力棒:[${arr}]`) })
Promise的问题: 并没有彻底消灭嵌套: 比如: .then(dong) .then(function(){ console.log("比赛结束") }).catch(function(err){ 错误处理 })
ES7: async await
解决: ES7: async await 可按照传统的同步指定的代码一样,编写异步代码顺序执行 只要多个异步任务需要顺序执行: (async function(){ 同步代码; var 返回值=await 异步函数() 同步代码; })(); 其中: await可让整段匿名函数自调暂时挂起,等待当前异步函数执行完,在执行后续代码! 强调: es7的async和await仅仅简化的是promise函数调用的部分。而并没有简化Promise函数的定义。且,如果想用await,则异步函数必须定义为支持promise的样式。 错误处理: 如果await修饰的异步函数中调用了err()方法,打开了错误的门,则await会认为是程序错误。 应该用try{}catch(err){}来解决 强调: 只有async下的try catch才能捕获异步任务中的错误。没在async下的js基础中所学的try catch是不能捕获异步任务的!因为普通js基础中的try catch属于主程序,不会等待异步任务执行,就已经结束了。即使异步任务出错,try catch因为早就结束了,所以根本捕获不到。 为什么await配合try catch就可以捕获异步任务中的错误呢? 因为await可留住当前程序中的一切代码,等待异步函数执行完。try catch就有可能捕获到异步任务中的错误。
function a(){ return new Promise( function(door,err){ var bang="a的接力棒"; console.log(`a 拿着${bang} 起跑...`); setTimeout(function(){ if(Math.random()<0.6){ console.log(`a 拿着${bang} 到达终点!`); //2. 在异步函数最后一句话执行完,开门通知下一个人可以开始执行。 console.log(`a开门!把${bang}交给下一个人`) door(bang); }else{ console.log(`呀!a摔倒了!!!`); err("a摔倒了"); } },6000) } ) } function b(bang){ return new Promise( function(door,err){ console.log(`b 拿着${bang} 起跑...`); setTimeout(function(){ if(Math.random()<0.6){ console.log(`b 拿着${bang} 到达终点!`); //2. 在当前异步任务结束后,自动调用开关door()开门通知下一个函数可以开始执行 console.log(`b开门!把${bang}交给下一个人`) door(bang) }else{ console.log(`呀!b摔倒了!!!`); err("b摔倒了"); } },2000) } ) } function dong(bang){ return new Promise( function(door){ console.log(`c 拿着${bang} 起跑...`); setTimeout(function(){//异步! console.log(`c 拿着${bang} 到达终点!`) console.log("c开门!") door(); },4000) } ) } (async function(){ try{ var bang=await a(); //door就相当于return bang //await代替了.then() bang=await b(bang); await c(bang); console.log("比赛结束"); }catch(err){//代替了.catch() console.log(err); console.log("集体退赛!"); } })();
- 点赞
- 收藏
- 分享
- 文章举报
相关文章推荐
- ReactNative踩坑日志——使用async/await语法解决网络请求的异步导致的指令执行顺序错乱问题
- 利用async和await异步操作解决node.js里面fs模块异步读写,同步结果的问题
- async+await解决回调地狱问题
- ES6/7/8新特性Promise,async,await,fetch带我们逃离异步回调的深渊
- ajax回调函数执行顺序带来的同步异步问题
- 回调地狱(就是让代码按照顺序执行)***Promise - ES6新对象
- 解决js异步问题的方法--async和await(ES7)
- 前端踩坑小结:多个异步请求在同一个函数里面执行时的同步问题之promise的用法。
- ajax回调函数执行顺序带来的同步异步问题
- ajax回调函数执行顺序带来的同步异步问题
- ES6的异步操作之promise用法和async函数的具体使用
- 前端开发都应该懂的事件循环(event loop)以及异步执行顺序(setTimeout、promise和async/await)
- es6——promise(解决回调地狱的问题)及 jQuery 中的 promise 应用
- 详解koa2学习中使用 async 、await、promise解决异步的问题
- js中的for循环与异步回调函数执行顺序问题
- 使用ES6的Promise完美解决回调地狱
- 使用ES6的Promise完美解决回调地狱
- ES6 Promise实际项目用法 (避免回调地狱)
- ie兼容es6,ie兼容ES6的方法,包括箭头函数,Promise,async,await
- javascript ES6 新特性之 Promise,ES7 async / await