面向面试题和实际使用谈promise

匿名 (未验证) 提交于 2019-12-02 21:53:52

  上一篇博客我们在现实使用和面试角度讲解了Promise(原文可参考《面向面试题和实际使用谈promisethen()then,代码流程不能很好的表示执行流程。

为什么是async/await

  在es6中,我们可以使用Generator函数控制流程,如下面这段代码:

function* foo(x) {     yield x + 1;     yield x + 2;     return x + 3; }

  我们可以根据不断地调用Generator对象的next()方法来控制函数的流程。但是这样仿佛不是那么的语义化。因此,在ES6中封装了Generator函数的语法糖async函数,但是将其定义在了es7中。ES7定义出的asyncAsyncAsyncAsync()Asyncawait*yieldasyncthen()方法进行调用。

  那么,我们通过一段小小的代码来说明async/await函数的用法:

    未使用async/await的定时函数:

fn = () => {   return new Promise((resolve, reject) => {     setTimeout(() => {       resolve(1)     }, 2000)   }) } const Fn = () =>{   fn().then((res) => {     console.log(res)   }) } Fn() console.log(2)

  我相信能看到这里的各位程序员大佬应该都知道这段代码的输出状况:先打印2,2s之后打印出1。

    使用async/await的定时函数:

fn = () => {   return new Promise((resolve, reject) => {     setTimeout(() => {       resolve(1)     }, 2000)   }) } const Fn = async () => {   await fn().then((res) => {     console.log(res)   }) } Fn() console.log(2)

  这一段函数的输出状况是:2s后打印1,然后打印2。

  那么,why?

  我们在字面上理解这两个单词async和await:async的意思是异步,async用于定义一个异步函数,该函数返回一个Promise。;await的意思是等待,Promise是一个承诺,await也是一个承诺。Promise的承诺是将返回值输出到then的回掉函数里面,无论是成功还是失败。await的承诺是无论刮风还是下雨,我都会等你完成在做其他的步骤。因此,在上面的运用了async/await的代码中,会等待fn完全运行完成并且异步的回调完成对返回值的处理之后在开始进行下一步操作的。其原理是将异步函数转变为同步操作。

实际运用

  在上周的工作中,我在一段基于node完成的爬虫操作中多次运用async/await来控制程序的执行流程:

//伪代码 let axiosArr = []; for (let i = 0, len = arr.length; i < len; i++) {   let params = qs.stringify({     'param': arr[i].index,   })   axiosArr.push(axios.post(url, params, {     headers   })) } /* *上面的循环是循环抓取2345条数据,平均每个数据要访问16个接口 *用axios.all同时询问,当返回结束后将返回值处理 *然后将返回值存储到mongodb数据库中 */ await axios.all(axiosArr).then(   axios.spread(function () {     for (let i = 0, len = arguments.length; i < len; i++) {       let str = `${unescape(arguments[i].data.replace(/\\u/g, '%u'))}`;       str = basics.subStr(basics.deletN(basics.deletS(basics.cutStr(str))));       concentArr[i].concent = str     }     mg.mongodbMain({       name: obj.name,       alias: obj.alias,       type: type,       url: obj.url,       drugsConcent: concentArr     })   }))

  其实操作就这么点,大家看一下代码都会懂。但是问题是,当我不使用async/await时,会产生的情况是会先访问2000+个数据,不断访问其16个接口,但是由于promise的then的回调函数为异步的,会挂起,而不是直接将数据存到数据库中。这貌似和我们预想的不一样啊。因此,我在这里使用了async/await函数,使用同步处理异步操作,将promise同步化,当axios.all访问完成这每一条数据的16个接口后,直接将数据存储到数据库中,然后才会走到循环的下一层,依旧是访问下一条数据的16个接口。

async/await的身后事

  我们说过了async

const delay = timeout => new Promise(resolve=> setTimeout(resolve, timeout)); async function f(){     await delay(1000);     await delay(2000);     await delay(3000);     return 'done'; }  f().then(v => console.log(v));// 6s之后打印'done'

rejectcatch

async function e(){     throw new Error('error'); } e().then(v => console.log(v)) .catch( e => console.log(e));//抛出的错误会被catch捕捉到

  并且,async有一个和promise.all相似的特性,就是内部一点有一个await函数报错,后续的就不再执行了

let fn1 = ()=>{     return new Promise((resolve,reject) => {         setTimeout(()=>{             reject('故意抛出错误');         },500);     }); }  let fn2 = ()=>{     return new Promise((resolve,reject)=>{         setTimeout(()=>{             resolve(1);         },500);     }); }  let getList = async ()=>{     let a = await fn1();     let b = await fn2();     return {first: a,second:b}; } getList().then(result=> {     console.log(result); }).catch(err=> {     console.log(err);// 由于fn1的报错,async的状态直接变成了rejected });

  当Promise出现的时候,我们仿佛看到了回调地狱的灭亡。当Async/Await出现时,异步终于不是一件困难的事情。

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!