今天有幸好碰到一个bug,让我知道了之前我对await async 的理解有点偏差。

错误的理解

之前我一直以为  await 后面的表达式,如果是直接返回一个具体的值就不会等待,而是继续执行async function 中的函数, 如下demo:

 method () {
getParams () {
let params = {}
if (this.serachFrom.time !== 0) {
params.month = this.serachFrom.time.substr(5, 2)
params.year = this.serachFrom.time.substring(0, 4)
}
return params
},
async testNoAwait () {
console.log('run testNoAwait')
return 'this is no await'
},
async testAsync () {
console.log('run testAsync')
let params = this.getParams()
const data = await this.$store.dispatch('initSchemeTimeTest', params)
return data
},
async test () {
console.log('test start')
const v1 = await this.testNoAwait()
console.log(v1)
const v2 = await this.testAsync()
console.log(v2)
console.log(v1, v2)
}
},
created () {
console.log('this is run created ')
this.test()
console.log('test last ...')
console.log('test end ...')
}

如上程序我之前认为   await this.testNoAwait() 会直接执行完不会等待,继续执行   console.log(v1),如果这样那么是一个错误的理解。

实际上MDN描述的暂停执行,并不是真正的暂停,而是让出了线程(跳出async函数体)然后继续执行后面的语句。

完整 demo code

vue  created

async created () {
console.log('this is run created ')
this.test()
// let data = this.test()
// console.log(data)
console.log('test last ...')
console.log('test end ...')
this.testSayHello()
}

vue  methods

testSayHello () {
console.log('this is run hello')
},
getParams () {
let params = {}
if (this.serachFrom.time !== 0) {
params.month = this.serachFrom.time.substr(5, 2)
params.year = this.serachFrom.time.substring(0, 4)
}
return params
},
testNoAwait () {
console.log('run testNoAwait')
return 'this is no await'
},
async testAsync () {
console.log('run testAsync')
let params = this.getParams()
const data = await this.$store.dispatch('initSchemeTimeTest', params)
return data
},
async test () {
console.log('test start')
const v1 = await this.testNoAwait()
console.log(v1)
const v2 = await this.testAsync()
console.log(v2)
console.log(v1, v2)
}

vuex 中

// actions
async initSchemeTimeTest ({commit, state, dispatch}, params) {
console.log('run initSchemeTimeTest')
const data = await schemeListTest(params)
console.log('开始返回结果')
commit(types.SCHEME_DATA_TIME_LIST, data)
return data
}

services api 中

注意在 testAsync 中  dispatch 了 initSchemeTimeTest,然后在调用了服务端的 schemeListTest

export async function schemeListTest (params) {
console.log('this is run server')
const data = await postTest(`/provid/spot/dailydeclareschemestatus/list`, params)
return data
}

common 中封装的 axiosServer

export function postTest (url, params) {
return new Promise(async (resolve, reject) => {
try {
console.log('this is run common')
const {
data:
{
respHeader,
respBody
}
} = await axiosServer({
url,
type: 'post',
params: {
reqBody: params
}
})
if (respHeader.needLogin && process.env.NODE_ENV !== 'development') {
Message.error(respHeader.message)
location.href = condition.frontDomain + `/login?redirect=${encodeURI(condition.frontDomain + '/spot/race')}`
reject(respHeader.message)
}
if (respHeader.resultCode === 0) {
resolve(respBody || respHeader.message)
} else {
if (respHeader.resultCode === 21050 && respBody) {
Message.error(respHeader.message)
resolve(respBody)
} else if (respHeader.message === '您没有该应用的权限') {
location.href = 'frame.huidiancloud.com'
} else {
Message.error(respHeader.message)
reject(respHeader.message)
}
}
} catch (e) {
reject(e)
Message.error('系统繁忙,请稍后再试!')
}
})
}

如果按照之前的理解那么这个应该是输出了 run testNoAwait  之后继续输出  this is no await 。

控制台运行结果:

执行顺序

js是单线程(同时只能干一件事情),

以上测试的关键点在于当程序碰到await 时,把后面的表达式执行一次,然后把resolve 函数或者reject 函数(await 操作符会把表达式的结果解析成promise 对象) push 回调队列,接着跳过当前这个async function ,执行async function 后面的代码,如上面代码中,执行 this.testNoAwait() 之后就跳过 this.test()这个方法,执行了

console.log('test last ...')
console.log('test end ...')
this.testSayHello()

至于什么时候知道这个promise 对象的状态,这就是事件循环的事情了,监听到这个异步的状态事件改变时,如果执行环境栈是空的那么就会执行取出回调队列中的回调,推入执行环境栈,然后继续async function 后面的语句。

vue 开始执行created 生命周期

输出:this is run created

输出:test start

执行:testNoAwait  // 关键

输出 :run testNoAwait 之后 跳过 test() 函数 执行created 后面的语句

输出:test last ... 、test end ... 、this is run hello

程序回到

const v1 = await this.testNoAwait()

如果监听到这个异步事件完成 则开始执行 后面的代码所以会

输出:this is no await

下面这个 await 跟上面同理

const v2 = await this.testAsync()

await 后面的表达式执行一次,如果里面存在await 也是同理继续执行下去,执行完之后,跳过这个async function 等到异步操作完成了继续回到 const v2 这里执行。

这里需要注意的是在common 中的postTest 中构造的Promise 对象是立即执行传入的function 所以在 services api 输出了 this is run server  之后接着输出 this is run common

因为上面的列子不是很方便看,所以我写了一个简单的测试 :

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" name="viewport">
<meta content="yes" name="apple-mobile-web-app-capable">
<meta content="black" name="apple-mobile-web-app-status-bar-style">
<meta content="telephone=no,email=no" name="format-detection">
<meta name="App-Config" content="fullscreen=yes,useHistoryState=yes,transition=yes">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>async await demo</title>
</head>
<body>
<h1>async await demo</h1>
</body>
<script> async function async1() {
console.log('async1 start')
await async2()
console.log('async1 end')
}
async function async2() {
console.log('async2')
await async3()
}
async function async3() {
console.log('async3')
await async4()
console.log('async4 end')
}
async function async4() {
return new Promise(function (resolve, reject) {
console.log('async4')
resolve()
})
}
console.log('script start')
setTimeout(function () {
console.log('setTimeout')
}, 0)
async1();
new Promise(function (resolve) {
console.log('promise1')
resolve();
}).then(function () {
console.log('promise2')
})
console.log('script end') // script start async1 start async2 async3 async4 promise1 script end promise2 async4 end async1 end setTimeout </script>
</html>

async awiat 执行顺序关键点

  1. 事件循环机制
  2. 回调队列
  3. 执行环境栈、入栈、出栈
  4. Promise 的构造函数是立即执行,但是他的成功、失败的回调函数是一个异步执行的回调
  5. Promise 的回调优先于 setTimeout 的任务队列
  6. async 返回promise 对象
  7. await 表达式的作用和返回值

总结

1、js 是单线程(同时只能做一件事情),在js引擎内部异步的处理是跟事件循环机制、以及回调队列有关

2、构造的promise 对象是立即执行传入的function

3、async function 是返回一个promise 对象

4、await 操作符会把表达式的结果进行解析成promise 对象

最新文章

  1. tp框架之留言板练习
  2. java ide 导出可运行jar包
  3. nginx 设置反响代理实现nginx集群
  4. WatiN框架学习
  5. Django数据库操作
  6. MYSQL数据库性能调优之二:定位慢查询
  7. Java [Leetcode 171]Excel Sheet Column Number
  8. ZABBIX作集中式NGINX性能监控的注意要点
  9. Android - 支持不同的设备 - 支持不同的屏幕
  10. java 双击jar包操作
  11. 那些年我遇到的ERP顾问
  12. Django的form表单之文件上传
  13. python使用rabbitMQ介绍三(发布订阅模式)
  14. PyQt5之布局管理
  15. Python_Mix*生成器,生成器函数,推导式,生成器表达式
  16. html:常见行内标签,常见块级标签,常见自闭合标签
  17. Linux内核入门到放弃-内存管理-《深入Linux内核架构》笔记
  18. python函数后面有多个括号怎么理解?
  19. luogu3707 相关分析 (线段树)
  20. 启动Jmeter4.0 后弹出命令窗口提示信息是什么意思?

热门文章

  1. extjs几个奇怪的错误
  2. SQLServer2008只能编辑前面200行数据
  3. Xdebug原理
  4. Final版本发布评论
  5. 对于beta发布的评论
  6. Docker(十一)-Docker commit创建镜像
  7. [转帖]Windows 内置端口转发功能
  8. maven依赖包冲突解决思路
  9. JSON中JObject和JArray的修改
  10. 一本通1622Goldbach’s Conjecture