当前位置: 首页 > news >正文

JS的运行机制的总结!

JS是单线程语言,为什么要一开始设计成单线程语言呢???

JS这门语言设计之初,一 是用来做 页面脚本,也就是客户端的一些简单交互,比如:表单验证这样的事情,二是用来操作DOM,如果JS开两个线程做事情,如果碰见两个线程在操作同一个DOM,那么,浏览器就会迷惑到底要相信哪一个线程的话。所以,为了避免未来JS发展太过于冗杂,JS从诞生以来就沿用单线程的底层设计在发展,并一直沿用至今。

同步和异步和任务队列:

正因为JS是单线程语言,所以同步和异步的概念就格外重要。JS所有的执行任务分为两种,一种是同步任务,一种是异步任务。 可以粗略地认为:同步任务执行在 执行栈上,异步任务放在任务队列中。 我们所写的按顺序普通执行的执行函数都放在主线程执行栈中。 所有的事件回调(例如:点击事件),setTimeout,setInterVal,Promise.then(()=>{})还有 $http()请求,都是异步任务,放置在执行队列中等待被执行。 所以JS的Event Loop机制如下: (1)所有同步任务都在主线程上执行,形成一个执行栈(execution context stack)。 (2)执行栈之外,还存在一个"任务队列"。只要异步任务有了运行结果,就在"任务队列"之中放置一个事件。 (3)一旦"执行栈"中的所有同步任务执行完毕,系统就会读取"任务队列",看看里面有哪些事件。那些对应的异步任务,于是结束等待状态,进入执行栈,开始执行。 (4)主线程不断重复上面的第三步。 然而,还没完的是, 上面所说的任务队列并非那么简单,任务队列之中还会细化为两种模式:MacroTasks和MicroTasks。 通常地: MacroTasks包括有:
鼠标,键盘等回调事件
setTimeout
setInterval
setImmediate
requestAnimationFrame I/O UI rendering

MicroTasks包括有:

process.nextTick

Promise.then().then().then()

MVVM框架例如vue的Object.observe等等、

JS的事件循环运行机制就可以看做一个 执行栈+无限个任务队列(MacroTasks) 所构成。而MicroTasks就是附着在 主线程或者每一个 任务队列(MacroTasks)末尾的 小任务队列。每一次任务队列中的任务执行完后,JS就会去检测当前附着的MicroTasks里面有没有任务,有就执行MicroTasks里的任务,没有,就执行下一个大的任务队列(MacroTasks)里的任务。依次循环。直至终结。

面试经典题:

  console.log(1)
}, 0);
new Promise(function executor(resolve) {
  console.log(2);
  for( var i=0 ; i<10000 ; i++ ) {
    i == 9999 && resolve();
  }
  console.log(3);
}).then(function() {
  console.log(4);
});
console.log(5);
复制代码

执行顺序:2,3,5,4,1 1.由于setTimeout 定时函数 定义出来,首先就被放置在下一个任务队列(MacroTasks)中,所以即便第二个参数设置是0,也会延迟到主线程内所有任务执行完后再执行。 2.碰到New Promise()函数,Promise函数内部是按正常流程的主线程中执行的,所以首先输出2。for循环依旧是在主线程里执行,按正常执行,然后碰到输出3,则再正常输出3。 3.碰到then()方法,由于then()内部是放在任务队列中,由于主线程还未执行完,所以then()里的执行被搁置。 4.输出5在主线程中,然后输出5,当前首个任务队列在执行栈中执行完毕。 5.主线程跑完了,接下来就是重点。由上面所说,Promise属性MicroTasks,所以在当前任务队列执行完后,进去MicroTasks队列去看看有没有Promise.then()之类MicroTasks,发现有,则执行输出4。 6.最后,当前首个任务队列执行完了,附着在任务队列最后的MicroTasks队列也执行完了,就可以执行下一个 任务队列(MacroTasks),即一开始被setTimeout放置的console.log(1),即最后 输出1。

经典例题:

for (var i = 0; i < 5; i++) {
  setTimeout(function() {
    console.log(i);
  }, 1000 * i);
}
复制代码

由于for循环内是一个 压入任务队列(MacroTasks)的setTimeout异步函数,所以for循环内部并没有去执行那setTimeout内部的匿名回调函数,但确实执行了第二个参数1000*i,定义了然后执行到了下一个 任务队列(MacroTasks),然后进入到setTimeout的回调函数中去,由于此时,对于回调的匿名函数内部来说,i已经累加到5了,所以,i=5是一个定值。所以会持续输出五个5,由于第二个参数确实在for循环中执行了,所以是在第0秒,第1秒,第2秒,第3秒,第4秒期间持续输入的五个5。

那如何改成 正常地输出 0,1,2,3,4呢?

for (var i = 0; i < 5; i++) {
  (function(i) {
    setTimeout(function() {
      console.log(i);
    }, i * 1000);
  })(i);
}
复制代码

或者: var i 改成let i

for (let i = 0; i < 5; i++) {
    setTimeout(function() {
      console.log(i);
    }, i * 1000);
}
复制代码

通过立即执行函数或 var 改成let,来自己构成一个封闭的作用域, 原理是: 让i 处在 运行的时候当前的作用域,而非 i处在定义的时候i当前的作用域

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

相关文章:

  • 从SQL Server CloudDBA 看云数据库智能化
  • 夯实爪哇基础-数据类型,内存
  • Hibernate关联关系注解配置简单理解
  • 五大好用的开源MySQL管理工具推荐
  • day--42 前端基础小结
  • 【python】【基础】mac安装python3及pip
  • Using system view: sys.sysprocesses to check SqlServer's block and deadlock
  • JavaScript中for in 和for of的区别
  • 对于你们驳来驳去的《停止学习框架》,我有话说!
  • Linux下调整ext3分区大小【转】
  • 大快搜索获评“2018中国大数据基础软件领域领军企业”
  • leetcode讲解--894. All Possible Full Binary Trees
  • React降级配置及Ant Design配置
  • 解决iOS10的Safari下Meta设置user-scalable=no无效的方法
  • 中国智慧城市“热战”的2018
  • CSS 提示工具(Tooltip)
  • Iterator 和 for...of 循环
  • SQL 难点解决:记录的引用
  • 不上全站https的网站你们就等着被恶心死吧
  • 彻底搞懂浏览器Event-loop
  • 创建一个Struts2项目maven 方式
  • 基于Mobx的多页面小程序的全局共享状态管理实践
  • 基于OpenResty的Lua Web框架lor0.0.2预览版发布
  • 基于组件的设计工作流与界面抽象
  • 蓝海存储开关机注意事项总结
  • 前端性能优化——回流与重绘
  • 使用Swoole加速Laravel(正式环境中)
  • 跳前端坑前,先看看这个!!
  • 为什么要用IPython/Jupyter?
  • 数据可视化之下发图实践
  • 整理一些计算机基础知识!
  • ​queue --- 一个同步的队列类​
  • ​TypeScript都不会用,也敢说会前端?
  • !!Dom4j 学习笔记
  • #!/usr/bin/python与#!/usr/bin/env python的区别
  • (教学思路 C#之类三)方法参数类型(ref、out、parmas)
  • (论文阅读23/100)Hierarchical Convolutional Features for Visual Tracking
  • (一)Java算法:二分查找
  • (已解决)什么是vue导航守卫
  • .NET CORE 3.1 集成JWT鉴权和授权2
  • .net FrameWork简介,数组,枚举
  • .NET MVC第五章、模型绑定获取表单数据
  • .NET/C# 在 64 位进程中读取 32 位进程重定向后的注册表
  • .NET面试题解析(11)-SQL语言基础及数据库基本原理
  • .NET中GET与SET的用法
  • .NET中winform传递参数至Url并获得返回值或文件
  • ??如何把JavaScript脚本中的参数传到java代码段中
  • [ 2222 ]http://e.eqxiu.com/s/wJMf15Ku
  • [ vulhub漏洞复现篇 ] AppWeb认证绕过漏洞(CVE-2018-8715)
  • [ vulhub漏洞复现篇 ] ECShop 2.x / 3.x SQL注入/远程执行代码漏洞 xianzhi-2017-02-82239600
  • []串口通信 零星笔记
  • [android] 请求码和结果码的作用
  • [AndroidStudio]_[初级]_[修改虚拟设备镜像文件的存放位置]
  • [C#]winform部署PaddleOCRV3推理模型
  • [CSS]CSS 的背景