1、async/await的优势node
1)方便级联调用:即调用依次发生的场景;python
2)同步代码编写方式: Promise使用then函数进行链式调用,一直点点点,是一种从左向右的横向写法;async/await从上到下,顺序执行,就像写同步代码同样,更符合代码编写习惯;编程
3)多个参数传递: Promise的then函数只能传递一个参数,虽然能够经过包装成对象来传递多个参数,可是会致使传递冗余信息,频繁的解析又从新组合参数,比较麻烦;async/await没有这个限制,能够当作普通的局部变量来处理,用let或者const定义的块级变量想怎么用就怎么用,想定义几个就定义几个,彻底没有限制,也没有冗余工做;多线程
4)同步代码和异步代码能够一块儿编写: 使用Promise的时候最好将同步代码和异步代码放在不一样的then节点中,这样结构更加清晰;async/await整个书写习惯都是同步的,不须要纠结同步和异步的区别,固然,异步过程须要包装成一个Promise对象放在await关键字后面;并发
5)基于协程: Promise是根据函数式编程的范式,对异步过程进行了一层封装,async/await基于协程的机制,是真正的“保存上下文,控制权切换……控制权恢复,取回上下文”这种机制,是对异步过程更精确的一种描述;异步
6)async/await是对Promise的优化: async/await是基于Promise的,是进一步的一种优化,不过在写代码时,Promise自己的API出现得不多,很接近同步代码的写法;async
2、协程函数式编程
// 传统的生产者-消费者模型是一个线程写消息,一个线程取消息,经过锁机制控制队列和等待,但一不当心就可能死锁。 // 若是改用协程,生产者生产消息后,直接经过yield跳转到消费者开始执行,待消费者执行完毕后,切换回生产者继续生产,效率极高: import time def consumer(): r = '' while True: n = yield r if not n: return print('[CONSUMER] Consuming %s...' % n) time.sleep(1) r = '200 OK' def produce(c): c.next() n = 0 while n < 5: n = n + 1 print('[PRODUCER] Producing %s...' % n) r = c.send(n) print('[PRODUCER] Consumer return: %s' % r) c.close() if __name__=='__main__': c = consumer() produce(c)
[PRODUCER] Producing 1... [CONSUMER] Consuming 1... [PRODUCER] Consumer return: 200 OK [PRODUCER] Producing 2... [CONSUMER] Consuming 2... [PRODUCER] Consumer return: 200 OK [PRODUCER] Producing 3... [CONSUMER] Consuming 3... [PRODUCER] Consumer return: 200 OK [PRODUCER] Producing 4... [CONSUMER] Consuming 4... [PRODUCER] Consumer return: 200 OK [PRODUCER] Producing 5... [CONSUMER] Consuming 5... [PRODUCER] Consumer return: 200 OK
注意到consumer函数是一个generator(生成器),把一个consumer传入produce后:函数
首先调用c.next()启动生成器;性能
而后,一旦生产了东西,经过c.send(n)切换到consumer执行;
consumer经过yield拿到消息,处理,又经过yield把结果传回;
produce拿到consumer处理的结果,继续生产下一条消息;
produce决定不生产了,经过c.close()关闭consumer,整个过程结束。
整个流程无锁,由一个线程执行,produce和consumer协做完成任务,因此称为“协程”,而非线程的抢占式多任务。
3、async关键字
1)代表程序里面可能有异步过程: async关键字代表程序里面可能有异步过程,里面能够有await关键字;固然所有是同步代码也不要紧,可是这样async关键字就显得多余了;
2)非阻塞: async函数里面若是有异步过程会等待,可是async函数自己会立刻返回,不会阻塞当前线程,能够简单认为,async函数工做在主线程,同步执行,不会阻塞界面渲染,async函数内部由await关键字修饰的异步过程,工做在相应的协程上,会阻塞等待异步任务的完成再返回;
3)async函数返回类型为Promise对象: 这是和普通函数本质上不一样的地方,也是使用时重点注意的地方;
(1)return newPromise();这个符合async函数本意;
(2)return data;这个是同步函数的写法,这里是要特别注意的,这个时候,其实就至关于Promise.resolve(data);仍是一个Promise对象,可是在调用async函数的地方经过简单的=是拿不到这个data的,由于返回值是一个Promise对象,因此须要用.then(data => { })函数才能够拿到这个data;
(3)若是没有返回值,至关于返回了Promise.resolve(undefined);
4)无等待 联想到Promise的特色,在没有await的状况下执行async函数,它会当即执行,返回一个Promise对象,而且绝对不会阻塞后面的语句,这和普通返回Promise对象的函数并没有二致;
5)await不处理异步error: await是无论异步过程的reject(error)消息的,async函数返回的这个Promise对象的catch函数负责统一抓取内部全部异步过程的错误;async函数内部只要有一个异步过程发生错误,整个执行过程就中断,这个返回的Promise对象的catch就能抓取到这个错误;
5)async函数的执行: async函数执行和普通函数同样,函数名带个()就能够了,参数个数随意,没有限制,也须要有async关键字;只是返回值是一个Promise对象,能够用then函数获得返回值,用catch抓整个流程中发生的错误;
async function testAsync() { return "hello async"; } const result = testAsync(); // 返回一个Promise对象 console.log(result); // async函数返回的是一个Promise对象,async函数(包括函数语句、函数表达式、Lambda表达式)会返回一个Promise对象,若是在函数中return一个直接量,async会把这个直接量经过Promise.resolve() 封装成 Promise 对象;
// async函数返回的是一个Promise对象,因此在最外层不能用await获取其返回值的状况,应该使用原始的方式:then()链来处理这个Promise对象 testAsync().then(v => { console.log(v); // 输出 hello async });
4、await关键字
1)await只能在async函数内部使用:不能放在普通函数里面,不然会报错;
2)await关键字后面跟Promise对象:在Pending状态时,相应的协程会交出控制权,进入等待状态,这是协程的本质;
3)await是async wait的意思: wait的是resolve(data)的消息,并把数据data返回,好比下面代码中,当Promise对象由Pending变为Resolved的时候,变量a就等于data,而后再顺序执行下面的语句console.log(a),这真的是等待,真的是顺序执行,表现和同步代码几乎如出一辙;
const a = await new Promise((resolve, reject) => { // async process ... return resolve(data); }); console.log(a);
4)await后面也能够跟同步代码: 不过系统会自动将其转化成一个Promsie对象,好比:
const a = await 'hello world' // 至关于 const a = await Promise.resolve('hello world'); // 跟同步代码是同样的,还不如省事点,直接去掉await关键字 const a = 'hello world';
5)await对于失败消息的处理: await只关心异步过程成功的消息resolve(data),拿到相应的数据data,至于失败消息reject(error),不关心不处理;对于错误的处理有如下几种方法供选择:
(1)让await后面的Promise对象本身catch;
(2)也可让外面的async函数返回的Promise对象统一catch;
(3)像同步代码同样,放在一个try...catch结构中;
async componentDidMount() { // 这是React Native的回调函数,加个async关键字,没有任何影响,可是能够用await关键字 // 将异步和同步的代码放在一个try..catch中,异常都能抓到 try { let array = null; let data = await asyncFunction(); // 这里用await关键字,就能拿到结果值;不然,没有await的话,只能拿到Promise对象 if (array.length > 0) { // 这里会抛出异常,下面的catch也能抓到 array.push(data); } } catch (error) { alert(JSON.stringify(error)) } }
6)await对于结果的处理: await是个运算符,用于组成表达式,await表达式的运算结果取决于它等的东西,若是它等到的不是一个Promise对象,那么await表达式的运算结果就是它等到的东西;若是它等到的是一个Promise对象,await就忙起来了,它会阻塞其后面的代码,等着Promise对象resolve,而后获得resolve的值,做为await表达式的运算结果;虽然是阻塞,但async函数调用并不会形成阻塞,它内部全部的阻塞都被封装在一个Promise对象中异步执行,这也正是await必须用在async函数中的缘由;
5、套路分析一
// 异步过程封装 function sleep(ms) { return new Promise((resolve) => { setTimeout(() => { resolve('sleep for ' + ms + ' ms'); }, ms); }); }
// 定义异步流程,能够将按照须要定制,就像写同步代码那样 async function asyncFunction() { console.time('asyncFunction total executing:'); const sleep1 = await sleep(2000); console.log('sleep1: ' + sleep1); const [sleep2, sleep3, sleep4]= await Promise.all([sleep(2000), sleep(1000), sleep(1500)]); console.log('sleep2: ' + sleep2); console.log('sleep3: ' + sleep3); console.log('sleep4: ' + sleep4); const sleepRace = await Promise.race([sleep(3000), sleep(1000), sleep(1000)]); console.log('sleep race: ' + sleepRace); console.timeEnd('asyncFunction total executing:'); return 'asyncFunction done.' // 这个能够不返回,这里只是作个标记,为了显示流程 }
// 像普通函数调用async函数,在then函数中获取整个流程的返回信息,在catch函数统一处理出错信息 asyncFunction().then(data => { console.log(data); // asyncFunction return 的内容在这里获取 }).catch(error => { console.log(error); // asyncFunction 的错误统一在这里抓取 }); console.log('after asyncFunction code executing....'); // 这个表明asyncFunction函数后的代码, // 显示asyncFunction自己会当即返回,不会阻塞主线程
// 执行结果 after asyncFunction code executing.... sleep1: sleep for 2000 ms sleep2: sleep for 2000 ms sleep3: sleep for 1000 ms sleep4: sleep for 1500 ms sleep race: sleep for 1000 ms asyncFunction total executing:: 5006.276123046875ms asyncFunction done.
代码分析
after asyncFunction code executing....代码位置在async函数asyncFunction()调用以后,反而先输出,这说明async函数asyncFunction()调用以后会立刻返回,不会阻塞主线程;
sleep1: sleep for 2000 ms这是第一个await以后的第一个异步过程,最早执行,也最早完成,说明后面的代码,不管是同步和异步,都在等他执行完毕;
sleep2 ~ sleep4这是第二个await以后的Promise.all()异步过程,这是“比慢模式”,三个sleep都完成后,再运行下面的代码,耗时最长的是2000ms;
sleep race: sleep for 1000 ms这是第三个await以后的Promise.race()异步过程,这是“比快模式”,耗时最短sleep都完成后,就运行下面的代码,耗时最短的是1000ms;
asyncFunction total executing:: 5006.276123046875ms这是最后的统计总共运行时间代码,三个await以后的异步过程之和:
1000(独立的) + 2000(Promise.all) + 1000(Promise.race) = 5000ms
这个和统计出来的5006.276123046875ms很是接近,说明上面的异步过程,和同步代码执行过程一致,协程真的是在等待异步过程执行完毕;
asyncFunction done.这个是async函数返回的信息,在执行时的then函数中得到,说明整个流程完毕以后参数传递的过程;
6、套路分析二
/** * 传入参数 n,表示这个函数执行的时间(毫秒) * 执行的结果是 n + 200,这个值将用于下一步骤 */ function takeLongTime(n) { return new Promise(resolve => { setTimeout(() => resolve(n + 200), n); }); } function step1(n) { console.log(`step1 with ${n}`); return takeLongTime(n); } function step2(n) { console.log(`step2 with ${n}`); return takeLongTime(n); } function step3(n) { console.log(`step3 with ${n}`); return takeLongTime(n); }
// Promise方式调用 function doIt() { console.time("doIt"); const time1 = 300; step1(time1) .then(time2 => step2(time2)) .then(time3 => step3(time3)) .then(result => { console.log(`result is ${result}`); console.timeEnd("doIt"); }); } doIt(); // c:\var\test>node --harmony_async_await . // step1 with 300 // step2 with 500 // step3 with 700 // result is 900 // doIt: 1507.251ms
// async/await方式调用 async function doIt() { console.time("doIt"); const time1 = 300; const time2 = await step1(time1); const time3 = await step2(time2); const result = await step3(time3); console.log(`result is ${result}`); console.timeEnd("doIt"); } doIt();
7、套路分析三
function step1(n) { console.log(`step1 with ${n}`); return takeLongTime(n); } function step2(m, n) { console.log(`step2 with ${m} and ${n}`); return takeLongTime(m + n); } function step3(k, m, n) { console.log(`step3 with ${k}, ${m} and ${n}`); return takeLongTime(k + m + n); }
// Promise方式调用 function doIt() { console.time("doIt"); const time1 = 300; step1(time1) .then(time2 => { return step2(time1, time2) .then(time3 => [time1, time2, time3]); }) .then(times => { const [time1, time2, time3] = times; return step3(time1, time2, time3); }) .then(result => { console.log(`result is ${result}`); console.timeEnd("doIt"); }); } doIt();
// async/await方式调用 async function doIt() { console.time("doIt"); const time1 = 300; const time2 = await step1(time1); const time3 = await step2(time1, time2); const result = await step3(time1, time2, time3); console.log(`result is ${result}`); console.timeEnd("doIt"); } doIt(); // c:\var\test>node --harmony_async_await . // step1 with 300 // step2 with 800 = 300 + 500 // step3 with 1800 = 300 + 500 + 1000 // result is 2000 // doIt: 2907.387ms