js为什么是单线程?

主要是因为最开始javascript是单纯的服务于浏览器的一种脚步语言(那时候没有nodejs)。浏览器是为了渲染网页,通过dom与用户交互,如果一个线程需要给dom执行click事件,而另一个进程要删除这个dom,这2个动作可能同时进行,也可能先后进行(像java,c#等语言中会引入锁的概念,这样会变得异常复杂),那么就会造成很多不可预料的错误。

所以,为了避免复杂性,从一诞生,JavaScript就是单线程,这已经成了这门语言的核心特征。为了利用多核CPU的计算能力,HTML5提出Web Worker标准,允许JavaScript脚本创建多个线程,但是子线程完全受主线程控制,且不得操作DOM。所以,这个新标准并没有改变JavaScript单线程的本质。

浏览器是多线程的

浏览器打开一个tab,就会单独开一个进程,这个进程包含多个线程
主要包含的线程有:

GUI渲染线程
负责渲染浏览器界面,解析HTML,CSS,构建DOM树和RenderObject树,布局和绘制等。
当界面需要重绘(Repaint)或由于某种操作引发回流(reflow)时,该线程就会执行
注意,GUI渲染线程与JS引擎线程是互斥的,当JS引擎执行时GUI线程会被挂起(相当于被冻结了),GUI更新会被保存在一个队列中等到JS引擎空闲时立即被执行。JS引擎线程
也称为JS内核,负责处理Javascript脚本程序。(例如V8引擎)
JS引擎线程负责解析Javascript脚本,运行代码。
JS引擎一直等待着任务队列中任务的到来,然后加以处理,一个Tab页(renderer进程)中无论什么时候都只有一个JS线程在运行JS程序
同样注意,GUI渲染线程与JS引擎线程是互斥的,所以如果JS执行的时间过长,这样就会造成页面的渲染不连贯,导致页面渲染加载阻塞。事件触发线程
归属于浏览器而不是JS引擎,用来控制事件循环(可以理解,JS引擎自己都忙不过来,需要浏览器另开线程协助)
当JS引擎执行代码块如setTimeOut时(也可来自浏览器内核的其他线程,如鼠标点击、AJAX异步请求等),会将对应任务添加到事件线程中
当对应的事件符合触发条件被触发时,该线程会把事件添加到待处理队列的队尾,等待JS引擎的处理
注意,由于JS的单线程关系,所以这些待处理队列中的事件都得排队等待JS引擎处理(当JS引擎空闲时才会去执行)定时触发器线程
传说中的setInterval与setTimeout所在线程
浏览器定时计数器并不是由JavaScript引擎计数的,(因为JavaScript引擎是单线程的, 如果处于阻塞线程状态就会影响记计时的准确)
因此通过单独线程来计时并触发定时(计时完毕后,添加到事件队列中,等待JS引擎空闲后执行)
注意,W3C在HTML标准中规定,规定要求setTimeout中低于4ms的时间间隔算为4ms。异步http请求线程
在XMLHttpRequest在连接后是通过浏览器新开一个线程请求
将检测到状态变更时,如果设置有回调函数,异步线程就产生状态变更事件,将这个回调再放入事件队列中。再由JavaScript引擎执行。
上面列出的线程之间,有一个重要的规则是:GUI渲染线程与JS引擎线程互斥,那么我们可以得出以下结论JS阻塞页面加载,那么在js运行的这段时间内,GUI的渲染会停止,这段时间内的界面交互,DOM的重绘与回流会停止,会被保存到待执行队列中,直到js线程空闲,才会执行这些队列。
我们用下面的一段代码和运行结果来说明这个机制:

    

可以看到,一开始网页和动画正常运行,但是开始执行计算斐波那契数列后,动画就停止了,页面也停止响应鼠标的click事件了,直到recurFib(40)计算出结果后,动画才开始继续执行,而期间积攒的click事件也在一起被执行。这就解释了GUI渲染线程与JS引擎线程互斥。由于这个弊端HTML5提出Web Worker标准。

利用Web Worker开启一个子线程

Web Worker 有以下几个使用注意点。

1.同源限制
分配给 Worker 线程运行的脚本文件,必须与主线程的脚本文件同源。
2.DOM 限制
Worker 线程所在的全局对象,与主线程不一样,无法读取主线程所在网页的 DOM 对象,也无法使用document、window、parent这些对象。但是,Worker 线程可以navigator对象和location对象。
3.通信联系
Worker 线程和主线程不在同一个上下文环境,它们不能直接通信,必须通过消息完成。
4.脚本限制
Worker 线程不能执行alert()方法和confirm()方法,但可以使用 XMLHttpRequest 对象发出 AJAX 请求。
5.文件限制
Worker 线程无法读取本地文件,即不能打开本机的文件系统(file:),它所加载的脚本,必须来自网络。
创建Worker时,JS引擎向浏览器申请开一个子线程(子线程是浏览器开的,完全受主线程控制,而且不能操作DOM)
JS引擎线程与worker线程间通过特定的方式通信(postMessage API,需要通过序列化对象来与线程交互特定的数据)。
下面我们用worker的相关api来解决上面卡顿的问题。

    
// test.js子线程代码// 通过监听message来接受主线程中的消息addEventListener('message', function(res) {    // 子线程向主线程中发生消息    // 计算斐波那契数列,这个数列从第3项开始,每一项都等于前两项之和。    if(res.data === 'start') {        // 开始运算        console.log('收到主线程消息,开始运算')        function recurFib(n) {            if(n < 2){                // 主动关闭子线程                // this.close()                return n ;            }else {                return recurFib(n-1)+recurFib(n-2)            }        }        console.time("运算时间:")        // 计算n为40的结果        var count = recurFib(40)        console.timeEnd("运算时间:")        // 向主线程发送消息        console.log('运算完毕,发送消息给主线程!')        this.postMessage(count);    }})

运行结果:

可以看到整个运行过程动画没有卡顿,也能响应click事件,所以在我们遇到大型计算的时候,请单独开启一个worker子线程来解决js线程阻塞GUI线程的问题。上文中只涉及到一部分worker API。

兼容性

可以看到除了Opera Mini浏览器,连IE都能使用了,所以兼容性问题不大。

总结

  1. 由于javaScript的最初设计特点,采用了单线程的运行机制。
  2. 浏览器是多个线程相互协作来工作的,但是GUI渲染线程与JS引擎线程互斥
  3. js线程在运行时,会锁死GUI渲染线程,为了利用多核CPU的计算能力,HTML5提出Web Worker标准。
  4. Web Worker的使用有一些限制,比如说:同源限制,DOM限制,文件限制等,但能解决在js需要大量计算工作时,页面卡顿的问题。
  5. Web Worker实际上是js线程的一个子线程,理论上js还是单线程的。

学习如逆水行舟,不进则退,前端技术飞速发展,如果每天不坚持学习,就会跟不上,我会陪着大家,每天坚持推送博文,跟大家一同进步,希望大家能关注我,第一时间收到最新文章。

主进程中发生了一个javascript错误_知道html5 Web Worker标准吗?能实现JavaScript的多线程?相关推荐

  1. JavaScript多线程之HTML5 Web Worker

    在博主的前些文章Promise的前世今生和妙用技巧和JavaScript单线程和浏览器事件循环简述中都曾提到了HTML5 Web Worker这一个概念.在JavaScript单线程和浏览器事件循环简 ...

  2. 主进程中发生javascript错误_你知道 JavaScript 中的错误对象有哪些类型吗?

    每当 JavaScript 中发生任何运行时错误时,都会引发Error对象.在许多情况下,我们还可以扩展这些标准Error对象,以创建我们自己的自定义Error对象. 属性 Error 对象具有2个属 ...

  3. excel 发生了一个oracle错误_但无法从,太好了,财务使用Excel公式报错原因大合集!以后再出错就这么解决...

    ▲ 导 读 日常使用公式常会于遇到错误值,有些时候我们会跟个无头苍蝇似的,不知道如何是好.如果我们能看懂错误值,会让我们事半功倍,快速找出错误的原因. 一起来看看来盘点下有哪些常见错误吧. 1.#N/ ...

  4. 【QT】震惊,一个由于QT只有.pro文件引起的世界难题。本文解决QT只有.pro的问题以及在项目中添加文件时,发生了一个编码错误的问题。

    震惊,一个由于QT只有.pro文件引起的世界难题!! 新手必看,避雷!!!不要相信网上那些人,他们文章中看不中用,正所谓印证了网络上的一句话:一人创作,万人模仿啊.和某手某音差不多!!# 概述:问题的 ...

  5. 项目中发生的一个奇葩问题

    项目中发生的一个奇葩问题: 现象 本地点击按钮,画面正常,不发生err. 服务器上点按钮,画面报错 列索引无效. 报错信息 org.springframework.jdbc.Uncategorized ...

  6. 创建一个矩形类的子类——正方形类,类中定义求面积方法、重写求周长的方法.在主类中,输入一个正方形边长,创建正方形对象,求正方形的面积和周长

    题目: 编写一个应用程序,创建一个矩形类,类中具有长.宽两个成员变量和求周长的方法.再创建一个矩形类的子类--正方形类,类中定义求面积方法.重写求周长的方法.在主类中,输入一个正方形边长,创建正方形对 ...

  7. 深入理解javascript异步编程障眼法h5 web worker实现多线程

    0.从一道题说起 var t = true; setTimeout(function(){ t = false; }, 1000); while(t){ } alert('end'); 1 2 3 4 ...

  8. 代码中避免懒加载错误_网站设计中应避免的5大错误

    代码中避免懒加载错误 The design of a website plays an imperative role in creating an effective and impressive ...

  9. android蓝牙错误码8,如何解决BluetoothGatt:Android中发生android.os.DeadObjectException错误?...

    我按照页面Bluetooth Low Energy开发Android 4.3的蓝牙低功耗. 我已经可以打开蓝牙,扫描设备并连接到BLE设备. 但是,在尝试连接到device(device.connec ...

最新文章

  1. 南洋理工大学科学家研发组装机器人,可以帮助用户组装椅子
  2. 黑鹰长期班.边程浪子系列教程
  3. 网络推广专员如何稳定搜索引擎首页排名全力以赴致力于网络推广
  4. android自定义push通知_android通过自定义toast实现悬浮通知效果的示例代码
  5. binwalk -e mysql_Binwalk的安装和使用
  6. lcd残影原理_为什么同样是高刷,OLED 可以比 LCD 优秀?
  7. 安装Google Object Detection API
  8. java 级联删除文件夹下的所有文件
  9. java 数组正则表达式_java正则表达式实现提取需要的字符并放入数组【ArrayList数组去重复功能】...
  10. webpack对脚本和样式的处理
  11. JWT Token在线编码生成
  12. 华为机试HJ85:最长回文子串
  13. 数学知识——高数速查手册
  14. sip 软电话 java源码,完美的 SIP 软电话
  15. android 调用百度翻译API 实现在线翻译
  16. Java培训学习之分词工具之HanLP介绍
  17. 《web全栈工程师》:中总结的20条军规和必读书单
  18. Attach、Detach和DeleteObject
  19. WPS表格:数据基本计算与引用-函数与表达式
  20. 信用评分卡 (part 5 of 7)

热门文章

  1. mysql客户端保存数据乱码_mysql客户端数据乱码问题
  2. 【转】Dicom中的Image Orientation/Position的理解
  3. 【转】0.SharePoint服务器端对象模型 之 序言
  4. 【转】JPA、Hibernate和Mybatis区别和总结
  5. mysql一个事务多个log_MySQL识别一个binlog中的一个事物
  6. 【2018ACM山东省赛 - C】Cities(最小生成树变形优化,贪心思维)
  7. 【牛客 - 551C】CSL 的密码(后缀数组,后缀自动机,随机算法)
  8. 【牛客 - 317D】小a与黄金街道(数论,tricks)
  9. *【CodeForces - 202C 】Clear Symmetry (思维,找规律,特判)
  10. 重读经典:《Momentum Contrast for Unsupervised Visual Representation Learning》