js异步编程终级解决方案 async/await

 

在最新的ES7(ES2017)中提出的前端异步特性:async、await。

async、await是什么

 

async顾名思义是“异步”的意思,async用于声明一个函数是异步的。而await从字面意思上是“等待”的意思,就是用于等待异步完成。并且await只能在async函数中使用

通常async、await都是跟随Promise一起使用的。为什么这么说呢?因为async返回的都是一个Promise对象同时async适用于任何类型的函数上。这样await得到的就是一个Promise对象(如果不是Promise对象的话那async返回的是什么 就是什么);

await得到Promise对象之后就等待Promise接下来的resolve或者reject。

async、await解决了什么问题

 

先来看下没有async/await之前js是如何处理异步操作的:

传统的回调地狱式写法:

Promise改进后的写法:

async/await改进后:

 

async、await写法

 

先来看下同步的写法

1 console.log(1);
2 
3 setTimeout(function () {
4   console.log(2);
5 }, 1000);
6 
7 console.log(3);

 下图是输出结果:

 

 

可以看到输出的顺序并不是我们代码中所写的那样,下面来看下async、await是如何解决这个问题的

 1 (async function () {
 2 
 3   console.log(1);
 4 
 5   await new Promise(function (resolve, reject) { 
7
setTimeout(function () { 8 console.log(2); 9 resolve(); 10 }, 1000); 11 }); 12 13 console.log(3); 14 15 }())

 

可以看到这中写法的输出已经符合了我们的预期,中间还多输出了一个Promise对象,这个原理可以用MDN上的官方定义来解释一下。

先来看下async是如何定义的

When an async function is called, it returns a Promise. When the async function returns a value,
the Promise will be resolved with the returned value. When the async function throws an exception
or some value, the Promise will be rejected with the thrown value.
这里说了三件事情
  • async函数会返回一个Promise对象;
  • 如果async函数中是return一个值,这个值就是Promise对象中resolve的值;
  • 如果async函数中是throw一个值,这个值就是Promise对象中reject的值;

再来看下await的定义

An async function can contain an await expression, that pauses the execution of the async
function and watis for the passed Promise's resolution, and then resumes the async
function's execution and returns the resolved value.
这里是说await会暂停当前async函数的执行,等待后面的promise的计算结果后再继续当前的async函数。
 
看到这里就明白了,首先,await只能在async里面;然后,await后面要跟一个promise对象;

常规的promise对象会被js先暂存到eventloop(事件队列)中,因为js是单线程执行的,等执行栈空了之后,才会将事件队列中的事件取出放入执行栈中执行。
 
上述代码中先是将整段代码改造成了一个async(async可以用于任何函数)函数,然后又将setTimeOut改造成了一个Promise对象。
 
这里我做了一下实验,如果改造后的Promise对象不加resolve()会是什么情况:
 1 (async function () {
 2 
 3   console.log(1);
 4 
 5   await new Promise(resolve => {
 6     setTimeout(() => {
 7       console.log(2);
 8     }, 1000);
 9   });
10   console.log(3);
11 }())

可以看到结果是这个样子,也就是说如果await后面等待的Promise对象如何不进行resolve() 的话,async函数就无法继续(至少我现在是这样理解的)。那如果await后面等的不是Promise对象呢,async还能继续走下去吗。

这里我写了个简单的代码测试了一下:

 1 function getSomething() {
 2     console.log("something");
 3 }
 4 
 5 async function testAsync() {
 6     console.log("hello async");
 7 }
 8 
 9 async function test() {
10     await getSomething();
11     await testAsync();
12 }
13 
14 test();

显而易见,如果await后面等是普通函数的话,那就会照常执行,和不加await是一样的。


总结一下,async/await就是为了解决异步回调而生的,它可以让你的异步代码写的像同步的一样具有良好的可读性,以上就是本人对async/await的一些理解,不足之处请指正,谢谢。

 

 
 
 
 

 

posted on 2019-04-18 11:50  拉通对齐端到端  阅读(988)  评论(0编辑  收藏  举报

导航