1.其他异步操作传统异步操作Generator的异步操作是异步的:任务的间断执行,跳转执行,当一个任务被阻塞时,主线程去执行其他任务,当被阻塞的任务收到一个执行信号时,它是再次加入任务队列1.1传统异步操作传统异步操作回调函数事件监听发布/订阅Promise对象1.1.1回调函数(callback)将一个任务分成多个段,以嵌套形式执行fs.readFile('/etc/passwd','utf-8',function(err,data){if(err)throwerr;console.log(data);});readFile的第三个参数是回调函数,只有在文件请求成功后才会调用回调函数可以实现程序回调地狱的异步执行//不同的任务函数toEat(val,fn){setTimeout(()=>{fn(val)},2000);}functiontoDrink(val,fn){setTimeout(()=>{fn(val)},1000);}functiontoKTV(val,fn){setTimeout(()=>{fn(val)},500);}//顺序执行任务toDrink("吃火锅",data=>{console.log(data);toDrink("喝啤酒",data=>{console.log(data);toKTV("唱歌",data=>{console.log(data);})})})//"吃火锅"//"喝啤酒"//"唱歌"嵌套其他任务任务的回调函数其他任务也有回调函数,这样在出错时层层嵌套1.1.2Promise//任务封装PromisefunctiontoResolve(data,delay){constpromise=newPromise((resolve,reject)=>{setTimeout(()=>{resolve(data)},delay);})returnpromise}//不同任务functiontoEat(val){returntoResolve(val,2000)}functiontoDrink(val){returntoResolve(val,1000)}functiontoKTV(val){returntoResolve(val,500)}//顺序执行任务toEat("吃火锅").then(val=>{console.log(val);returntoDrink("喝啤酒")}).then(val=>{console.log(val);returntoKTV("singing")}).then(val=>{console.log(val);}).catch(res=>{console.log(res);})//吃火锅//drinkingbeer//singing定时执行回调函数改为定时更改Promise状态结构更清晰但是由于Promise对原任务的封装,代码冗余,由于then的积累,语义变得不清晰1.2.Generator的异步操作还是使用上面封装的Promise任务,使用Generator异步执行//Generator函数function*asyncJob(){letval1=yieldtoEat("吃火锅")console.log(val1);letval2=yieldtoDrink("喝啤酒")console.log(val2);letval3=yieldtoKTV("singing")console.log(val3);}//生成器函数的执行者functionrunGenerator(fn){letiter=fn()let{value,done}=iter.next()value.then(val1=>{让{value,done}=iter.next(val1)value.then(val2=>{let{value,done}=iter.next(val2)value.then(val3=>{iter.next(val3)})})})}//开始执行异步任务runGenerator(asyncJob)//吃火锅//喝啤酒//唱歌以toEat为例,观察异步任务是如何执行的。调用生成器函数的执行者调用生成器函数,返回一个迭代器对象第一次调用迭代器上的next方法:执行到第一个yield,调用toEat函数,返回一个Promise对象作为该迭代器的value属性next返回值,解构value的值并在value上调用然后:在resolveValue中接收value(会延迟2s),第二次调用next将接收到的value赋值给第一个yield,然后toEat返回的值可以在第一个yield和第二个yield之间处理。第二个next的返回值可以解构相同的操作,重点关注调动next后发生的事情next参数传递Promise处理和状态变化的原理2.异步函数Generator的语法糖——让异步操作更简单使用上面封装的Promisetask//生成器的异步任务asyncfunctionasyncJob(){letval1=awaittoEat("吃火锅")console.log(val1);letval2=awaittoDrink("喝啤酒")console.log(val2);letval3=awaittoKTV("sing")console.log(val3);}//开始执行异步任务asyncJob()//吃火锅//喝啤酒//唱歌将生成器中的星号*替换为async,替换生成器中的yield和yield和await相比生成器的异步操作,async函数不需要手写执行器。内置的执行器可以直接调用async函数来执行内部任务。async函数改进了生成器。后者引入了co模块,async函数有自己的执行器,这使得它可以像普通函数一样执行更好的语义。async和await的语义表达比asterisk*和yield更清晰、更广泛。co模块指定yieldonly可以是Thunk函数或Promise对象,async函数的await可以是Promise对象或原始类型的值。return的默认值Promise.resolve()被转换成一个Promise对象,然后可以对外使用来接收异步函数的2.1错误处理。众所周知,async返回一个Promise,并且可以在外部捕获错误。//生成器的异步任务asyncfunctionasyncJob(){letval1=awaittoEat("吃火锅").then(()=>{thrownewError("餐厅关门了")})console.log(val1);letval2=awaittoDrink("喝啤酒")console.log(val2);letval3=awaittoKTV("Singing")console.log(val3);}//开始执行异步任务asyncJob().catch(res=>{console.log(res);})//错误:当餐厅closures一个await语句失败,后面不执行,直接抛出错误。2.2try...catch//生成器的异步任务asyncfunctionasyncJob(){try{letval1=awaittoEat("吃火锅").then(()=>{thrownewError("餐厅关门了")})console.log(val1);}catch(e){console.log(e);}try{letval2=awaittoDrink("drinkbeer")console.log(val2);letval3=awaittoKTV("singing")console.log(val3);}catch(e){console.log(e);}}//开始执行异步任务asyncJob().catch(res=>{console.log(res);})//Error:therestaurantisclosed//喝啤酒//互相不影响的唱歌任务是放在不同的try...catch代码块中,相互影响放在同一个try...catch代码块中2.3async函数中的并发//Generator的异步任务async函数asyncJob(){letval=awaitPromise.all([toEat("吃火锅"),toDrink("喝啤酒")])console.log(val);letval3=awaittoKTV("Singing")console.log(val3);}//开始执行异步任务asyncJob().catch(res=>{console.log(res);})//['吃火锅','喝啤酒']//“唱歌”也可以使用Promise.any()Promise.race()等方法2.4使用async函数重写一个异步的forEachArray.prototype.asyncForEach=asyncfunction(callback,thisArg){for(leti=0;i
