详解JavaScript 的执行机制


Posted in Javascript onSeptember 18, 2020

一、关于javascript

javascript是一门单线程语言,在最新的HTML5中提出了Web Worker,但javascript是单线程这一核心仍未改变。

为什么js是单线程的语言?因为最初的js是用来在浏览器验证表单操纵DOM元素的。如果js是多线程的话,两个线程同时对一个DOM进行了相互冲突的操作,那么浏览器的解析是无法执行的。

Web Worker 的作用,就是为 JavaScript 创造多线程环境,允许主线程创建 Worker 线程,将一些任务分配给后者运行。在主线程运行的同时,Worker 线程在后台运行,两者互不干扰。等到 Worker 线程完成计算任务,再把结果返回给主线程。

二、javascript事件循环

当我们调用一个方法的时候,js会生成一个与这个方法对应的执行环境(context),又叫执行上下文。这个执行环境中存在着这个方法的私有作用域,上层作用域的指向,方法的参数,这个作用域中定义的变量以及这个作用域的this对象。 而当一系列方法被依次调用的时候,因为js是单线程的,同一时间只能执行一个方法,于是这些方法被排队在一个单独的地方。这个地方被称为执行栈。

js引擎遇到一个异步事件后并不会一直等待其返回结果,而是会将这个事件挂起,继续执行执行栈中的其他任务。

当一个异步事件返回结果后,js会将这个事件加入与当前执行栈不同的另一个队列,我们称之为事件队列。被放入事件队列不会立刻执行其回调,而是等待当前执行栈中的所有任务都执行完毕, 主线程处于闲置状态时,主线程会去查找事件队列是否有任务。如果有,那么主线程会从中取出排在第一位的事件,并把这个事件对应的回调放入执行栈中,然后执行其中的同步代码。如此反复,这样就形成了一个无限的循环。

三、setTimeout

setTimeout这个函数,是经过指定时间后,把要执行的任务加入到Event Queue中,又因为是单线程任务要一个一个执行,如果前面的任务需要的时间太久,那么只能等着。

setTimeout(() => {
 task()
},3000)

sleep(10000000)

上述代码执行task()需要的时间远远超过3秒,执行过程如下:

  • task()进入Event Table并注册,计时开始。
  • 执行sleep函数,很慢,非常慢,计时仍在继续。
  • 3秒到了,计时事件timeout完成,task()进入Event Queue,但是sleep还没执行完,只好等着。
  • sleep终于执行完了,task()终于从Event Queue进入了主线程执行。

  setTimeout(fn,0)的含义是,指定某个任务在主线程最早可得的空闲时间执行,意思就是不用再等多少秒了,只要主线程执行栈内的同步任务全部执行完成,栈为空就马上执行。

四、setInterval

   对于执行顺序来说,setInterval会每隔指定的时间将注册的函数置入Event Queue,如果前面的任务耗时太久,那么同样需要等待。

唯一需要注意的一点是,对于setInterval(fn,ms)来说,我们已经知道不是每过ms秒会执行一次fn,而是每过ms秒,会有fn进入Event Queue。

五、Promise与process.nextTick(callback)

Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。

所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理。

process.nextTick(callback)类似node.js版的"setTimeout",在事件循环的下一次循环中调用 callback 回调函数。

六、宏任务和微任务

  • macro-task(宏任务):包括整体代码script,setTimeout,setInterval
  • micro-task(微任务):Promise.then,process.nextTick

不同类型的任务会进入对应的Event Queue,比如setTimeout和setInterval会进入相同的Event Queue。

事件循环的顺序,决定js代码的执行顺序。

进入整体代码(宏任务)后,开始第一次循环。接着执行所有的微任务。然后再次从宏任务开始,找到其中一个任务队列执行完毕,再执行所有的微任务。

setTimeout(function() {
 console.log('setTimeout');
})

new Promise(function(resolve) {
 console.log('promise');
}).then(function() {
 console.log('then');
})

console.log('console');
  • 这段代码作为宏任务,进入主线程。
  • 先遇到setTimeout,那么将其回调函数注册后分发到宏任务Event Queue。
  • 接下来遇到了Promise,new Promise立即执行,因为new Promise回调函数中的代码是同步任务,then函数分发到微任务Event Queue。
  • 遇到console.log(),立即执行。
  • 好啦,整体代码script作为第一个宏任务执行结束,看看有哪些微任务?我们发现了then在微任务Event Queue里面,执行。
  • 第一轮事件循环结束了,我们开始第二轮循环,当然要从宏任务Event Queue开始。我们发现了宏任务Event Queue中setTimeout对应的回调函数,立即执行。
  • 结束。

七、async await

1.async 做一件什么事情?

带 async 关键字的函数,它使得你的函数的返回值必定是 promise 对象。

也就是,如果async关键字函数返回的不是promise,会自动用 Promise.resolve() 包装。如果async关键字函数显式地返回promise,那就以你返回的promise为准。

2.await 在等什么?

await等的是右侧「表达式」的结果。也就是说,右侧如果是函数,那么函数的return值就是「表达式的结果」。右侧如果是一个 'hello' 或者什么值,那表达式的结果就是 'hello'。

3.await 等到之后,做了一件什么事情?

await右侧表达式的结果,就是await要等的东西。等到之后,对于await来说,分2个情况:

  • 不是promise对象
  • 是promise对象

如果不是 promise , await会阻塞后面的代码,先执行async外面的同步代码,同步代码执行完,再回到async内部,把这个非promise的东西,作为 await表达式的结果。

如果它等到的是一个 promise 对象,await 也会暂停async后面的代码,先执行async外面的同步代码,等着 Promise 对象 fulfilled,然后把 resolve 的参数作为 await 表达式的运算结果。

4.示例

async function async1() {
 console.log('async1 start');
 await async2();
 console.log('async1 end');
}

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

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。
  • 打印出async1 start,执行到await,执行函数async2,打印出async2。
  • 此时await会阻塞async1后面的代码,会先执行async1外面的同步代码。
  • setTimeout放入事件循环的宏任务。接着执行到Promise,打印出promise1,promise.then放入事件循环的微任务。接着打印script end。
  • 现在async1外面的同步代码执行完毕,回到async1内部打印出async1 end。
  • 整体代码执行完毕,执行微任务promise.then,打印出promise2。
  • 最后执行宏任务setTimeout,打印setTimeout。

所以这段代码的执行顺序为:script start -> async1 start -> async2 -> promise1 -> script end -> async1 end -> promise2 -> setTimeout

以上就是详解JavaScript 的执行机制的详细内容,更多关于JavaScript 执行机制的资料请关注三水点靠木其它相关文章!

Javascript 相关文章推荐
基于jQuery的ajax功能实现web service的json转化
Aug 29 Javascript
兼容IE和FF的图片上传前预览js代码
May 28 Javascript
JavaScript中的console.time()函数详细介绍
Dec 29 Javascript
利用jQuery实现打字机字幕效果实例代码
Sep 02 Javascript
在 Angular2 中实现自定义校验指令(确认密码)的方法
Jan 23 Javascript
Extjs表单输入框异步校验的插件实现方法
Mar 20 Javascript
AngularJS实现自定义指令与控制器数据交互的方法示例
Jun 19 Javascript
react native实现往服务器上传网络图片的实例
Aug 07 Javascript
vue操作下拉选择器获取选择的数据的id方法
Aug 24 Javascript
vue interceptor 使用教程实例详解
Sep 13 Javascript
vue项目查看vue版本及cli版本的实现方式
Oct 24 Javascript
vue+element ui实现锚点定位
Jun 29 Vue.js
鸿蒙系统中的 JS 开发框架
Sep 18 #Javascript
React倒计时功能实现代码——解耦通用
Sep 18 #Javascript
浅谈鸿蒙 JavaScript GUI 技术栈
Sep 17 #Javascript
vue项目中播放rtmp视频文件流的方法
Sep 17 #Javascript
逐行分析鸿蒙系统的 JavaScript 框架(推荐)
Sep 17 #Javascript
vue项目实现多语言切换的思路
Sep 17 #Javascript
vue实现放大镜效果
Sep 17 #Javascript
You might like
PHP 选项及相关信息函数库
2006/12/04 PHP
使用phpQuery采集网页的方法
2013/11/13 PHP
php使用json_decode后数字对象转换成了科学计数法的解决方法
2017/02/20 PHP
不一样的文字闪烁 轮番闪烁
2009/11/11 Javascript
有关于JS辅助函数inherit()的问题
2013/04/07 Javascript
HTTP 304错误的详细讲解
2013/11/13 Javascript
js原型继承的两种方法对比介绍
2014/03/30 Javascript
通过url查找a元素应用案例
2014/04/29 Javascript
JS实现简单的顶部定时关闭层效果
2014/06/15 Javascript
JS控制网页动态生成任意行列数表格的方法
2015/03/09 Javascript
Backbone.js 0.9.2 源码注释中文翻译版
2015/06/25 Javascript
javascript中offset、client、scroll的属性总结
2015/08/13 Javascript
JavaScript面试开发常用的知识点总结
2016/08/08 Javascript
JS中正则表达式要注意lastIndex属性
2017/08/08 Javascript
bing Map 在vue项目中的使用详解
2018/04/09 Javascript
详解Vue iview IE浏览器不兼容报错(Iview Bable polyfill)
2019/01/07 Javascript
从0搭建vue-cli4脚手架
2020/06/17 Javascript
详解JavaScript数据类型和判断方法
2020/09/04 Javascript
Openlayers绘制聚合标注
2020/09/28 Javascript
[01:14:55]EG vs Spirit Supermajor 败者组 BO3 第三场 6.4
2018/06/05 DOTA
[02:38]DOTA2 夜魇暗潮2020活动介绍官方视频
2020/11/04 DOTA
Python两个字典键同值相加的几种方法
2019/03/05 Python
python mysql自增字段AUTO_INCREMENT值的修改方式
2020/05/18 Python
完美解决torch.cuda.is_available()一直返回False的玄学方法
2021/02/06 Python
CSS3条纹背景制作的实战攻略
2016/05/31 HTML / CSS
英国美术用品购物网站:Cass Art
2019/10/08 全球购物
EJB3推出JPA的原因
2013/10/16 面试题
开办化妆品公司创业计划书
2013/12/26 职场文书
楼面部长岗位职责范本
2014/02/14 职场文书
医学生职业生涯规划书范文
2014/03/13 职场文书
老师对学生的评语
2014/04/18 职场文书
勿忘国耻9.18演讲稿(经典篇)
2014/09/14 职场文书
乡镇党员群众路线教育实践活动对照检查材料思想汇报
2014/10/05 职场文书
离婚协议书应该怎么写
2014/10/12 职场文书
地震慰问信
2015/02/14 职场文书
八年级作文之一起的走过日子
2019/09/17 职场文书