【async/await】从小程序简单的登录逻辑说async/await

这篇文章拖了好久好久了... 上一篇的后续,从实际案例中进一步理解js异步。

上一篇: 【Promise】从小程序简单的登录逻辑说promise

如果还没看过上一篇可以先看看,从现实需求中理解promise是一个很好的思路。

接着上一篇末尾提出的问题,想拿到promise返回的值怎么办,来说一说async/await

需求

小程序登录调用wx.login接口,这个接口是异步的,返回一个code,后端用这个code换取session_key

具体的业务逻辑就不多说了,上一篇讲了一下。

上一篇文章中,我们已经封装了一个函数把小程序异步写法换成promise写法,这非常有用。

但问题是,因为code是后续逻辑必须的,所以要保证后面的代码在执行的时候已经拿到code。

直接使用Promise解决

再说说为什么会有回调地狱

题外话,其实这种异步调用中获取的内容是后续逻辑的必要条件的情况,就是产生回调地狱的原因。

原始的解决方案就是不断地嵌套回调来保证逻辑是按序执行的。

Promise的出现就是为了将这种不断嵌套的回调优化为链式调用,不光逻辑清晰了,函数的执行上下文也清晰了。


所以Promise是能解决我们的需求的。只需要把后续的逻辑一步步写在then里面就ok了。

后续逻辑中还有需要处理的异步,就再写一个then,总之then then就完事了。

这样做的好处是,可以用catch做异常捕获。

坏处自然很明显,全部的逻辑都要写在then里面,相当于你的逻辑代码就一条promise语句,丑。

更关键的是,如果是多个then的链式调用,其实Pormise的写法并不易于维护,也一点不优雅,我们期望的是能像写同步代码一样写异步。

像写同步代码一样写异步这就是为什么async/await被称为异步的完美解决方案。

async/await

先理解一句话,async/await本质就是Promise的语法糖

我认为理解async/await的最好角度是事件循环,看到有大佬写的一篇文章很不错, 虽然他标题是反过来的23333,但是值得一看。

从event loop到async await来了解事件循环机制

我在这里也简单讲一些要点

理解async/await

macro-task和micro-task

这里就不能只单纯局限于事件队列的表层概念了,一定要理解macro-task和micro-task。

简单来说,macro-task包含了:

  • 同步代码
  • setTimeout,setInterval和内部的回调函数

micro-task包含了:

  • Promise的then
  • process.nextTick

注意new Promise的部分是同步代码

事件循环
  • 同步代码作为一轮macro-task执行
  • 遇到setTimeout,setInterval将回调推入macro-task队列
  • 遇到Promise,把then推入当前macro-task的micro-task队列
  • 本轮macro-task全部执行后,执行全部micro-task
  • 执行下一轮macro-task
  • ...

这里的macro-task就是平时说事件循环时说的同步栈和事件队列。

不同的是,Promise的异步任务并不会被推入和setTimeout相同的任务队列,而是有专门的micro-task队列,并且每轮macro-task执行完之后都会清空micro-task队列。

换句话说,then作为micro-task会优先于setTimeout的回调执行。

上面的链接里有举例分析,我就不说了。

async/await机制

首先明确一下概念

  • async是用来声明函数的,async function() {...},就是声明异步函数。
  • await是写在表达式前面的,字面意思,等待表达式完成。表达式是所有的js表达式都行。
  • await必须写在async里面
为什么这是Promise的语法糖?

也有说是generator的语法糖,我对js的generator理解不够,有新的理解会来更新这篇文章

async函数实际返回一个Promise

async function f() {console.log(1)}
f()
// Promise {<resolved>: undefined}
复制代码

所以其实这就是Promise的封装。

说到这里还并不能很好得理解到底这糖到底甜在哪

下面我们通过await的机制进一步来理解

await的机制:

  • 如果等待的是一个同步的表达式,那直接拿到结果
  • 如果等待的是一个Promise,阻塞后续代码,等待Promise resolve,并将resolve的值作为表达式计算结果,可以进行赋值。

bb了这么多,终于到了解决开头提出来的问题的地方。想拿到promise返回的值怎么办?用await。

这里直接把我写的登录逻辑贴出来

// 登录的全局方法
// 该函数需要指定this指针
export async function login() {
  console.log('login...');
  var login = promisify(mpvue.login)
  var code = await login().then(res => res.code)
  console.log('get login code: ' + code)
  
  this.$http.post(
    this.$store.getters.loginAPI,
    {
      code: code
    }
  ).then( res => { 
    handleLoginRes.call(this, res) 
  }).catch(() => {
    ...
  })
}

复制代码

如果用Promise来解决

function login() {
  console.log('login...');
  var login = promisify(mpvue.login)
  login().then(res => {
     var code = res.code
     console.log('get login code: ' + code)
     this.$http.post(
     this.$store.getters.loginAPI,
     {
        code: code
     }).then( res => { 
        handleLoginRes.call(this, res) 
     }).catch(() => {
            ...
     })
  }
})
复制代码

这里只需要等待一个code,区别不大并不是那么明显,如果需要再等待两三个值呢,就成了各种资料里说的经典案例,我就不写了。

总之,await得以让Promise的链式调用转换为和同步代码一样的写法,看着就很爽很顺滑。

async/await实现深入理解

我在上面给阻塞加粗了,这个阻塞和平时说的阻塞不太一样,这就涉及到await的实现了,我也还没搞明白。这部分等我找时间搞懂了更。

转载于:https://juejin.im/post/5ce53f7ae51d45773e4189f6

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值