回调函数和Promise要理解Promise和Aysnc(Aysnc和Await是一起使用的,所以下面的Aysnc默认包含Aysnc和Await关键字),首先要理解JavaScript中的异步概念。//传统写法letcallback=function(value){console.log(value)}letresult=step1(function(value1){step2(value1,function(value2){step3(value2,function(value3){step4(value3,function(value4){//执行回调callback(value4)});});});});console.log(result)//Promise写入letresult=(newPromise(step1)).then(step2).then(step3).then(step4);console.log(result)在正常逻辑下不能异步。为了实现异步,JavaScript引入了回调函数(callback)的概念。即通过层层嵌套,在回调函数中返回最终的执行结果。为了解决嵌套过多、代码不可读的问题,出现了Promise。Promise要解决的问题就是去掉回调函数,异步执行的代码可以写成同步执行的形式。Promise必须与Aysnc和Await一起使用。使用Promise的地方,必须要用Await来标识,表明这是一个异步函数。必须等待Promise中的流程结束,才能执行后续流程。aysnc应该写在标有Await的外层函数上。asyncfunctionstep1(value){letvalue1=awaitstep2(value);}Aysnc和Await的用法就这么简单,告诉main函数这个函数是异步执行的,必须等它执行完才能进入下一个过程。Aysnc和Await起到声明的作用,真正实现异步的逻辑实际上是由Promise来承担的。functionstep1(param){returnnewPromise(function(resolve,reject){//执行mysql查询等耗时操作mysql_query(sql,[param]).then((r)=>{resolve(r)}).catch(e=>{reject(e)})}).then((r)=>{console.log('resolve',r)return'成功结果'}).catch((e)=>{console.log(e)return'failedresult'});}一个完整的Promise对象由三部分组成:参数resolve、reject。这部分可以是外部传入的回调函数,也可以简单标识一下。如果是简单的识别,则在正确执行后resolve?then,有错误则reject?catch。then不再是Promise主体的一部分,而是序列中的下一步。也就是说,如果需要,直接在Promise中传入参数,返回resolve之前的返回值,最后接收结果。如果没有return而有then,then的部分还是会被执行。Catch是链写方法的一部分。在Promise主体中拒绝后,将执行catch部分。有意思的是紧跟在Promise后面的catch(链式写法),只捕获Promise的部分,连内部抛出的异常都捕获不到。所以catch也写在mysql_query之后,用来捕捉mysql_query自身的错误。否则如果mysql_query失败,会报unhandledpromiserejectionwarning异常。PromiseAll的用法大家有没有注意到,Promise方法并不是立即返回,而是创建并返回一个Promise对象,这就是异步的本质。因为在写代码的时候,我们无法控制什么时候可以获取到返回值(web请求成功时,sql查询不会耗时太长等),只能建立获取结果的通道,最后结果会重回正轨。然而,Promise是针对单一任务的。如果一个业务需要批量处理,仅仅通过Promise是解决不了的。asyncfunctionsomeRequest(){letresult=truefor(leti=0;i<10;i++){result&&awaitstep1(i)}returnresult}比如这样一串异步请求,我想通过多个异步请求的结果,判断最后是否全部执行成功。但是通过for循环执行时,第一个请求,第2个,第3个,第4个...第n个请求之间没有顺序关系,系统不会等到第一个执行完,再执行第2个and3rdrequestssequentially,4...nthone,如果这样的话,不能体现batch的意思。而是同时发出n个请求,即同时新建n个promise,然后所有promise同步执行。其实在所有的await执行结束之前,遍历for循环,返回结果。异步就是我们无法控制结果的返回时间和执行成功与否。同步就是我们不关心返回的结果是什么,而是立即返回。在我们从等待过程中得到结果之前,我们根据初始化返回。为了解决多个Promise异步的问题,出现了PromiseAll。//统一执行awaitasyncfunctiondbFuc(db){letdocs=[{},{},{}];让promises=docs.map((doc)=>db.post(doc));letresults=awaitPromise.all(promises);console.log(results);}//批量执行awaitasyncfunctiondbFuc(db){letdocs=[{},{},{}];让promises=docs.map((doc)=>db.post(doc));让结果=[];for(letpromiseofpromises){results.push(awaitpromise);}console.log(results);}统一执行和批量执行的结果是一样的,目的是保证所有的Promise对象都执行完,只有得到result数组结果后才能执行后续流程。
