ES7-async/await学习

终结者T800
• 阅读 2426

前言

网上有很多关于async/await的学习文章,我也是通过这些文章学习了解async的,但是不总结一下,总觉得没有真正学到。如有错误的地方还请多多指出。

什么是async/await

有人说它是JS编程异步的“终极解决方案”,终不终极不知道,事物总是在发展的嘛,但是能被冠上这么个头衔也绝非等闲之辈了?。async是“异步的”,await是“等待”,async是形容词,await是动词,那么async形容的函数告诉别人这是个包含异步的“异步的函数”,而await要等待某个东西的到来。a/a给了我们重新使用try catch的权力,并且规定await必须写在async形容的函数中。使用a/a要对Promise有所理解,那还要从回调说起。

回调函数

JS是一根筋的(单线程),一次只执行一个任务,后面的要等前面的完成才行, 如果某个任务要占用很长时间,那么后面的任务就都要等着。所以

JS将任务的执行模式分成两种:同步(Synchronous)和异步(Asynchronous)。地址

回调函数就是“异步“的方法之一。大家对回调很熟啦,回调会产生一个问题-回调地狱,两层回调还好,三层似乎也可以接受,硬着头皮四层也行,五层要不要写,咬咬牙六层就好了。。。最后,一首杨宗纬的洋葱送给自己。一层一层剥开回调,找到最终的小可爱。
比如下面的栗子:

a1(function(res) {
  d2(res, function(newRes) {
    a3(newRes, function(finalRes) {
      console.log('a3: ' + finalRes);
    }, a1FCb);
  }, a2FailCb);
}, a3FailCb);

另外,当年我还年轻的时候,初试回调,在回调函数中花样百出的尝试return,在回调外面也取不到return的值,大概下面这个样子

var a = ''
function fool(){
  setTimeout(() => {
     return 'hi'// 或者
  }, 1000);
}
a = fool()
console.log(a) //undefined 因为setTimeout异步执行,a=fool()执行在timeout之前,而此时的fool()并内有return任何东西

回调让我们失去了直接“使用return”的方式,那来看看Promise。

Promise

顾名思义,promise是承诺的意思,承诺在未来是可以兑现的,promise可以有效的解决回调地狱,而且给了我们使用return的权力。只不过它的return仍是一个承诺。对于promise的学习可参考promise MDNPromise MDN

一个 Promise有以下几种状态:
pending: 初始状态,既不是成功,也不是失败状态。
fulfilled: 意味着操作成功完成。
rejected: 意味着操作失败。

如下一个利用Promise构造函数声明的实例

  new Promise(function(resolve,reject){//...})

resolve 和 reject 函数被调用时,分别将promise的状态改为fulfilled(完成)或rejected(失败),这两个状态不能同时出现,两个状态完成时,分别调用promise的then方法中对应的onfulfilled 和onrejected 函数。举个例子:

function a(val){
  return new Promise(function(resolve,reject){
    if(val === 1){
      resolve(val)
    } else {
      reject('bad val')
    }
  })  
}

函数a接收一个参数,返回一个promise实例,当参数是期望的1时,表示操作成功,其他值被认为操作失败。那么如果执行以下操作

a(1).then(function(res){
  console.log('onfulfilled '+ res)
},function(errMsg){
  console.log('onrejected '+ errMsg)
})
//会log出'onfulfilled 1'

该操作a(1)会调用函数a内部promise实例的resolve函数,把该promise的状态变成了fulfilled,所以之后会调用then函数里onfulfilled的函数。

另外,对于操作失败的状态,除了在then中指定对应的onreject函数外,也可以使用catch,使用catch的好处在于,如果是多个异步操作,只需要指定一个catch即可,不用为每层then都指定一个onreject函数。举个例子:

有如下三层回调:

fun1(function(res1){
  fun2(function(res1){
    var res2 = res1 + 'hello'
    fun3(function(res2){
      var res3 = res2 + 'hi'
      console.log('the final res ' + res3)
    },fun3FailCb)
  },fun2FailCb)
},fun1FailCb)

改成promise写法后:

fun1()
  .then(function(res1){
    return fun2(res1+'hello')
  })
  .then(function(res2){
    return fun3(res2+'hi')
  })
  .then(function(res3){
    console.log('the final res' + res3)
  })
  .catch(function(err){
    console.log('something bad occured')
  }) 

清爽很多。then的链写多了,看起来也很烦啊,有没有更简洁的方法?有!

async/await

async/await是一个语法糖,他和promise关系紧密,可参考async MDN

当调用一个 async 函数时,会返回一个 Promise 对象。当这个 async 函数返回一个值时,Promise 的 resolve 方法会负责传递这个值;当 async 函数抛出异常时,Promise 的 reject 方法也会传递这个异常值。

回到开篇说的,async所形容的函数告诉别人这是个包含异步的“异步的函数”,也就是async的函数会返回一个promise (同步的代码也没关系,只不过没啥意义了)。await要等的就是其他async函数返回的这个promise,promise状态成功,await等到的是resolve中的值,promise状态失败,await等到的是reject中的错误信息,换句话说,被try/catch中的catch到了。举个例子:

async function f1(val){
  if(val === 1){
    return val
  } else {
    throw 'not 1'
  }
} //调用f1(val)时,会自动返回一个包装好的promise
async function f2(val2){
 try{
   var res1 = await f1(val2)
   console.log('res1' , res1)
  }catch(errmsg){
   console.log('catch ', errmsg)
  }  
}

分别执行f2(1)和f2(3)查看log结果。

改写前面的三层回调

async function fun1(){
  return res1
}
async function fun2(val){
  return val + 'hello'
}

async function fun3(val){
  return val + 'hi'
}

async function fun4(){
 try{
   var res1 = await fun1()
   var res2 = await fun2(res1)
   var res3 = await fun3(res2)
   console.log('the final res ', res3)
   // other operation with res3/res2/res1...
 }catch(err){
   console.log('something bad')
 }
  
}

相当清爽。在async内,await会阻塞后面的程序执行,直到promise的状态完成(成功或失败)。

点赞
收藏
评论区
推荐文章
从 生成器 到 promise+async
本文主要讲解js中关于生成器的相关概念和作用,以及到后面结合promise实现es7中的async原理,你将学习到js中异步流程控制相关知识1、认识生成器思考如下代码:javascriptletx1functionfoo()xbar()console.log(x)//3functionbar(
亚瑟 亚瑟
4年前
Python Sanic 高并发服务开发指南
技术基础AsyncIOPython3.4开始引入AsyncIO(https://docs.python.org/3/library/asyncio.html)模块,使得Python也支持异步IO。3.5版本里添加了async/await关键字,使得异步IO代码编写更加方便。3.6和3.7版本继续进行了完善
郜小超 郜小超
4年前
用 async/await 来处理异步
一级标题昨天看了一篇vue的教程,作者用async/await来发送异步请求,从服务端获取数据,代码很简洁,同时async/await已经被标准化,是时候学习一下了。先说一下async的用法,它作为一个关键字放到函数前面,用于表示函数是一个异步函数,因为async就是异步的意思,异步函数也就意味着该函数的执行不会阻塞后面代码的执行。写一个async
Souleigh ✨ Souleigh ✨
4年前
理解 Javascript 中的 Async / Await
在本文中,我们将探讨async/await,对于每个Javascript开发人员来说,是异步编程的首选工具。如果您不熟悉javascript,请不要担心,本文将帮助您async/await从头开始理解。介绍async/await是javascript中的一种模式,可使您的代码以同步方式执行,但又不影响javascript的异步行为。定义异步功能要定义一
Karen110 Karen110
4年前
盘点JavaScript中async/await知识
大家好,我是进阶学习者。一、前言Async/await是以更舒适的方式使用promise的一种特殊语法,同时它也非常易于理解和使用。二、Asyncfunction让以async这个关键字开始。它可以被放置在一个函数前面。如下所示:asyncfunctionf()return1;在函数前面的“async”这个单词表达了一个简单的
九旬 九旬
4年前
一次搞懂-JavaScript之异步编程
前言异步,就是非同步....这节内容可能会有点枯燥,但是却是JavaScript中非常重要的概念,非常有必要去学习。目的提升开发效率,编写易维护的代码引子问题请求时候为什么页面卡死??js$.ajax(url:"www.xx.com/api",async:false,//truesuccess:function(result
Stella981 Stella981
3年前
Node.js的异步编程库async
官方文档:http://caolan.github.io/async/docs.html(https://www.oschina.net/action/GoToLink?urlhttp%3A%2F%2Fcaolan.github.io%2Fasync%2Fdocs.html)async包含了几个部分,Controlflow(异步流程处理)
Stella981 Stella981
3年前
C#异步编程 Task await的理解
async/await是C5.0中推出的,先上用法:staticvoidMain(stringargs){Console.WriteLine("主线程启动");Task<inttaskGetStrLengthAsync();Conso
Stella981 Stella981
3年前
Python's Async and Await 异步
Python'sAsyncandAwait异步展开function\_typeof(e){returne&&"undefined"!typeofSymbol&&e.constructorSymbol?"symbol":typeofe;}!function(e){i
Stella981 Stella981
3年前
CountDownLatch 源码解析—— await()
上一篇文章(https://www.oschina.net/action/GoToLink?urlhttp%3A%2F%2Fwww.cnblogs.com%2Fcuglkb%2Fp%2F8572239.html)说了一下CountDownLatch的使用方法。这篇文章就从源码层面说一下await()的原理。我们已经知道await能够让当前线程处
文盘Rust -- tonic-Rust grpc初体验 | 京东云技术团队
gRPC是开发中常用的开源高性能远程过程调用(RPC)框架,tonic是基于HTTP/2的gRPC实现,专注于高性能、互操作性和灵活性。该库的创建是为了对async/await提供一流的支持,并充当用Rust编写的生产系统的核心构建块。今天我们聊聊通过使用tonic调用grpc的的具体过程。