林大妈的JavaScript进阶知识(二):JS异步行为

JavaScript 是单线程执行的

JavaScript运行在浏览器中。浏览器是多线程的,但只分配了其中一条给JavaScript,作为它的主线程。对于编码者来说,JavaScript是单线程的。因此JavaScript中存在以下几种异步行为:

  1. 事件绑定(addEventListener)
  2. 定时器(setTimeout、setInterval)
  3. AJAX(axios)、fetch
  4. 所有跟Promise的resolve、reject相关的行为(generator、async/await)

JavaScript 异步执行情况

其中WEB API会执行类似setTimeout的倒数或发送AJAX请求这样的操作,而得到的返回值则会加入Event Queue中等待主栈为空时压栈执行。
练习题目

// 以下的程序将会按照如何的顺序执行?
async function async1 () {
    console.log('async1 start')
    await async2()
    console.log('async1 end')
}

async function async2 () {
    console.log('async2')
}

console.log('script start')

setTimeout(() => {
    console.log('setTimeout')
}, 0)

async1()

new Promise((resolve) => {
    console.log('promise1')
    resolve()
}).then(() => {
    console.log('promise2')
})

console.log('script end')

代码的基本分析:

  1. 第二到第十行,两个异步函数声明,不会输出东西
  2. 第十二到第二十七行,中间全部是函数执行的代码,可以把它看作主函数
  3. 第十二行是简单的输出语句
  4. 十四到十六行是一个setTimeout,通过前面的学习我们知道它会加入宏任务队列
  5. 第十八行是async1函数的执行,其中有一个async函数的嵌套,它把async2嵌套在了1中的await语句里
  6. 接着20行是一个Promise对象的声明,声明Promise对象需要传一个名为executor的参数,这个executor是会在声明的时候直接执行的,紧接着23行是一个then回调,通过前面的学习我们知道它会加入微任务队列
  7. 最后是一个普通的输出语句

因此这题的难点就是在async语句的嵌套中。首先,根据前面的分析,因为前面都是函数声明,不会输出内容,代码会先输出script start,然后setTimeout加入宏任务队列。接下来进入异步函数async1,我们知道,异步函数本质上是generator的语法糖,因此异步函数会一直同步地执行到await语句执行完毕,并且把下面的代码放到微任务队列中,因此代码执行到此还会依次输出async1 start和async2。紧接着创建Promise对象时executor被执行,输出promise1,并把then放入微任务中,最后输出script end。理论上说,到此JS主线程已经执行完毕,也就是主栈中是空的,接下来就要分别看微任务和宏任务队列了。看微任务队列中现在有两个Task,按刚才所说的顺序是先是async1 end,再是promise2,但此处V8引擎版本不同执行情况不同,有的版本是按照队列顺序执行,有的是先执行Promise再执行await后的语句(但新版本的V8引擎是属于先执行Promise这种情况的,因此会输出promise2和async1 end)。这种现象可能是由于底层实现中await转化为promise语句是放在加入队列前还是加入队列后执行的关系,但无论如何它们两个微任务都必会在宏任务前执行,因此最后会输出宏任务的setTimeout。

总结

异步编程需要比较细地掌握它们三个微任务:

  1. async/await
  2. Promise
  3. generator
    搞清楚基本的执行顺序即可,也不必要苛求每处都完全正确。

原文地址:https://www.cnblogs.com/BlogOfMotherLyn/p/12318419.html

时间: 2024-12-31 05:35:33

林大妈的JavaScript进阶知识(二):JS异步行为的相关文章

JavaScript进阶(二)

数学里面的"a>b",在JavaScript中还表示为a>b;数学中的"b大于a,b小于c"是a"a<b<c" 那么在JavaScript中可以用&&表示.如下: b>a && b<c //"&&"是并且的意思,读法"b大于a"并且"b小于c" 好比我们参加高考时,在进入考场前,必须出示准考证和身份证,两

JavaScript 进阶(二)变量作用域

局部变量陷阱 先看一段代码: function foo() { var a = "hello" b = "world" return a + b; } 这个函数执行完成之后返回helloworld,结果确实没有问题.但是里面有一个细节就是两个局部变量一个前边有var,另一个没有.这似乎并不影响执行,但是事实上没有var的话,这个变量就变成了全局变量.你在这个函数外面调用一下alert(b)试一下就知道了.一个莫名其妙冒出来的全局变量在有时候会引起匪夷所思的bug,所

JavaScript 进阶(一)JS的&quot;多线程&quot;

这个系列的文章名为“JavaScript 进阶”,内容涉及JS中容易忽略但是很有用的,偏JS底层的,以及复杂项目中的JS的实践.主要来源于我几年的开发过程中遇到的问题.小弟第一次写博客,写的不好的地方请诸位斧正,觉得还有一些阅读价值的请帮忙分享下.这个“JavaScript 进阶”是一个系列文章,请大家鼓励鼓励,我尽快更新.另外,如果你有比较好的话题,也可以在下面评论,我们一起研究提高. JS是多线程的吗? 多线程编程相信大家都很熟悉,比如在界面开发中,如果一个事件的响应需要较长时间,那么一般做

JavaScript进阶之路——认识和使用Promise,重构你的Js代码

一转眼,这2015年上半年就过去了,差不多一个月没有写博客了,"罪过罪过"啊~~.进入了七月份,也就意味着我们上半年苦逼的单身生活结束了,从此刻起,我们要打起十二分的精神,开始下半年的单身生活.大家一起加油~~ 一直以来,JavaScript处理异步都是以callback的方式,在前端开发领域callback机制几乎深入人心.在设计API的时候,不管是浏览器厂商还是SDK开发商亦或是各种类库的作者,基本上都已经遵循着callback的套路.近几年随着JavaScript开发模式的逐渐成

JavaScript进阶 九 JS实现本地文件上传至阿里云服务器

JS实现本地文件上传至阿里云服务器 前言 在前面的博客< JavaScript进阶(八)JS实现图片预览并导入服务器功能>(点击查看详情)中,实现了JS将本地图片文件预览并上传至阿里云服务器的操作.这次需要实现将本地打包好的文件上传至阿里云服务器.使用前面的图片文件上传方法无法完成此操作.操作界面如下: 思路 本地与服务端传输文件的格式应该是熟悉的Base64格式.首先需要将本地文件转换为Base64格式,传输至服务端后,在服务端再将Base64格式的文件转换为原始文件. 源码解析 控制器 /

JavaScript进阶--慕课网学习笔记

                     JAVASCRIPT-进阶篇 给变量取个名字(变量命名) 变量名字可以任意取,只不过取名字要遵循一些规则: 1.必须以字母.下划线或美元符号开头,后面可以跟字母.下划线.美元符号和数字.如下: 正确: mysum _mychar $numa1 错误: 6num  //开头不能用数字 %sum //开头不能用除(_ $)外特殊符号,如(%  + /等) sum+num //开头中间不能使用除(_ $)外特殊符号,如(%  + /等) 2.变量名区分大小写,

JavaScript 进阶问题列表

JavaScript 进阶问题列表 我在我的 Instagram 上每天都会发布 JavaScript 的多选问题,并且同时也会在这个仓库中发布. 从基础到进阶,测试你有多了解 JavaScript,刷新你的知识,或者帮助你的 coding 面试! 我每周都会在这个仓库下更新新的问题. 答案在问题下方的折叠部分,点击即可展开问题.祝你好运 1. 输出是什么? function sayHi() { console.log(name) console.log(age) var name = 'Lyd

JavaScript 进阶篇的学习~

---恢复内容开始--- 让你认识JS 你知道吗,Web前端开发师需要掌握什么技术?也许你已经了解HTML标记(也称为结构),知道了CSS样式(也称为表示),会使用HTML+CSS创建一个漂亮的页面,但这还不够,它只是静态页面而已.我们还需使用JavaScript增加行为,为网页添加动态效果.准备好,让JavaScript带你进入新境界吧! JavaScript能做什么? 1.增强页面动态效果(如:下拉菜单.图片轮播.信息滚动等) 2.实现页面与用户之间的实时.动态交互(如:用户注册.登陆验证等

javascript 学习小结 (二) by FungLeo

javascript 学习小结 (二) by FungLeo 前言 前面写过一个学习小结javascript 学习小结 JS装逼技巧(一) by FungLeo 那篇博文总结的东西还是比较多的. 但是JS有很多的内容,都是很有用的知识点,不可能一下子记住.因此,我的学习小结的会一直更新. 因为学习进度的不同,可能每篇博文的长短也不一样,有的学的东西多,就长点. 查询某个字符串在某个数组中的索引值 笨方法 我的基础比较差,所以很多东西是记不住的.因此,我在需要这样做的时候,我写了如下代码 var