JS是单线程的吗?
首先一个引子:为什么JavaScript是单线程的却能让AJAX异步发送和回调请求,还有setTimeout也看起来像是多线程的?
先看例子1:
function foo() {
console.log( 'first' );
setTimeout( ( function(){ console.log( 'second' ); } ), 5);
}
for (var i = 0; i < 1000000; i++) {
foo();
}
执行结果如下

先显示出10000个first,再显示出10000个second
Javascript是单线程的
因为JS运行在浏览器中,是单线程的,每个window一个JS线程,既然是单线程的,在某个特定的时刻只有特定的代码能够被执行,并阻塞其它的代码。
而浏览器是事件驱动的(Event driven),浏览器中很多行为是异步(Asynchronized)的,会创建事件并放入执行队列中。javascript引擎是单线程处理它的任务队列,你可以理解成就是普通函数和回调函数构成的队列。当异步事件发生时,如mouse click, a timer firing, or an XMLHttpRequest completing(鼠标点击事件发生、定时器触发事件发生、XMLHttpRequest完成回调触发等),将他们放入执行队列,等待当前代码执行完成。
异步事件驱动
前面已经提到浏览器是事件驱动的(Event driven),浏览器中很多行为是异步(Asynchronized)的,例如:鼠标点击事件、窗口大小拖拉事件、定时器触发事件、XMLHttpRequest完成回调等。
当一个异步事件发生的时候,它就进入事件队列。
浏览器有一个内部大消息循环,Event Loop(事件循环),会轮询大的事件队列并处理事件。例如,浏览器当前正在忙于处理onclick事件,这时另外一个事件发生了(如:window onSize),这个异步事件就被放入事件队列等待处理,只有前面的处理完毕了,空闲了才会执行这个事件。setTimeout也是一样,当调用的时候,js引擎会启动定时器timer,大约xxms以后执行xxx,当定时器时间到,就把该事件放到主事件队列等待处理(浏览器不忙的时候才会真正执行)。
浏览器不是单线程的
虽然JS运行在浏览器中,是单线程的,每个window一个JS线程,但浏览器不是单线程的,例如Webkit或是Gecko引擎,都可能有如下线程:
- javascript引擎线程
- 界面渲染线程
- 浏览器事件触发线程
- Http请求线程
很多童鞋搞不清,如果js是单线程的,那么谁去轮询大的Event loop事件队列?答案是浏览器会有单独的线程去处理这个队列。
Ajax异步请求是否真的异步?
很多童鞋搞不清楚,既然说JavaScript是单线程运行的,那么XMLHttpRequest在连接后是否真的异步?
其实请求确实是异步的,这请求是由浏览器新开一个线程请求(见前面的浏览器多线程)。当请求的状态变更时,如果先前已设置回调,这异步线程就产生状态变更事件放到 JavaScript引擎的事件处理队列中等待处理。当浏览器空闲的时候出队列任务被处理,JavaScript引擎始终是单线程运行回调函数。javascript引擎确实是单线程处理它的任务队列,能理解成就是普通函数和回调函数构成的队列。
总结一下,Ajax请求确实是异步的,这请求是由浏览器新开一个线程请求,事件回调的时候是放入Event loop单线程事件队列等候处理。
setTimeout(func, 0)为什么有时候有用?
写js多的童鞋可能发现,有时候加一个setTimeout(func, 0)非常有用,为什么?难道是模拟多线程吗?错!前面已经说过了,javascript是JS运行在浏览器中,是单线程的,每个window一个JS线程,既然是单线程的,setTimeout(func, 0)神奇在哪儿?那就是告诉js引擎,在0ms以后把func放到主事件队列中,等待当前的代码执行完毕再执行,注意:重点是改变了代码流程,把func的执行放到了等待当前的代码执行完毕再执行。这就是它的神奇之处了。它的用处有三个:
- 让浏览器渲染当前的变化(很多浏览器UI render和js执行是放在一个线程中,线程阻塞会导致界面无法更新渲染)
- 重新评估”script is running too long”警告
- 改变执行顺序
非阻塞js的实现(non-blocking javascript)
js在浏览器中需要被下载、解释并执行这三步。在html body标签中的script都是阻塞的。也就是说,顺序下载、解释、执行。
尽管Chrome可以实现多线程并行下载外部资源,例如:script file、image、frame等(css比较复杂,在IE中不阻塞下载,但Firefox阻塞下载)。
但是,由于js是单线程的,所以尽管浏览器可以并发加快js的下载,但必须依次执行(因为是单线程的)。所以chrome中image图片资源是可以并发下载的,但外部js文件并发下载没有多大意义。
要实现非阻塞js(non-blocking javascript)有两个方法:1. html5 2. 动态加载js
1. html5
defer
<script type="text/javascript" defer src="foo.js"></script>async
<script type="text/javascript" async src="foo.js"></script>2. 动态加载js
阻塞和非阻塞关注的是程序在等待调用结果(消息,返回值)时的状态.
JS是单线程的吗?的更多相关文章
- js的单线程和异步
前言 说到js的单线程(single threaded)和异步(asynchronous),很多同学不禁会想,这不是自相矛盾么?其实,单线程和异步确实不能同时成为一个语言的特性.js选择了成为单线程的 ...
- 多进程浏览器、多线程页面渲染与js的单线程
线程与进程 说到单线程,就得从操作系统进程开始说起.在早期的操作系统中并没有线程的概念,进程是能拥有资源和独立运行的最小单位,也是程序执行的最小单位.任务调度采用的是时间片轮转的抢占式调度方式,而进程 ...
- js异步梳理:1.从浏览器的多进程到JS的单线程,理解JS运行机制
大家很早就知道JS是一门单线程的语言.但是也时不时的会看到进程这个词.首先简单区分下线程和进程的概念 1. 简单理解进程 - 进程是一个工厂,工厂有它的独立资源 - 工厂之间相互独立 - 线程是工厂中 ...
- js的单线程与异步
一. js 是单线程和异步 1. js 是单线程的,js 的宿主环境(浏览器)是多线程的,实现异步. 2.js是单线程语言,浏览器值分配给js一个主线程,用来执行任务(函数),但一次只能执行一个任务, ...
- 为什么JS是单线程?JS中的Event Loop(事件循环)?JS如何实现异步?setimeout?
https://segmentfault.com/a/1190000012806637 https://www.jianshu.com/p/93d756db8c81 首先,请牢记2点: (1) JS是 ...
- 浏览器的多线程和js的单线程--前端易混淆知识科普(一)
问题:js是单线程的,页面是从上往下加载的,那么是不是第一个js没加载完成,第二个js就不加载?然后,引申出来一个问题就是,那css和图片呢?这之间的加载有相互影响吗? 1.什么是线程?什么是进程?什 ...
- JS高阶---为什么说JS是单线程执行的???
大纲: [主体] (1)如何证明JS运行是单线程的? 上述代码执行顺序结果为:fn()→timeout →timeout 接下来对上述代码做下修改 执行结果如右图所示 接下来点击确认,关闭弹框,再往后 ...
- 深入学习JS执行--单线程的JS
一.介绍 随着js不断学习,你可能会慢慢的好奇,用了这么久的js,却不知道这js在浏览器怎么被执行的,很尴尬.所以,我查阅很多资料来总结JS的执行过程,也分享出来,和大家一起学习. 本篇主要讲单线程的 ...
- 好程序员web前端分享如何理解JS的单线程
好程序员web前端分享如何理解JS单线程,JS本质是单线程的.也就是说,它并不能像JAVA语言那样,两个线程并发执行. 但我们平时看到的JS,分明是可以同时运作很多任务的,这又是怎么回事呢? 首先,J ...
随机推荐
- Vue.js 的精髓——组件
开篇:Vue.js 的精髓——组件 写在前面 Vue.js,无疑是当下最火热的前端框架 Almost,而 Vue.js 最精髓的,正是它的组件与组件化.写一个 Vue 工程,也就是在写一个个的组件. ...
- Flutter Map<String, dynamic> 、List<String> a-z 排序
字符串从 a-z 排序. Map<String, String> map = XXX, List<String> keys = map.keys.toList(); // ke ...
- PIE SDK影像坏线修复
1.算法功能简介 坏条带的由来:2003年5月31日,Landsat-7ETM+机载扫描行校正器(SLC) 故障,导致此后获取的影像出现了数据条带丢失,严重影响了Landsat ETM遥感影像的使用. ...
- post调试postman
载地址:https://www.getpostman.com/ 教程地址:http://www.cnblogs.com/s380774061/p/4624326.html
- Java生成树关系的菜单
1.菜单bean public class Menu { private String id; private String menuname; private String parentid; pr ...
- 每一次要fix的pr
1.TODO一定要加自己名字 2.写代码考虑别人的阅读,比如event这样很general的名字不要用,所以不用from sqlalchemy import event, 要用import sqlal ...
- Python RawSocket Syn
#!/bin/env python # -*- coding: UTF-8 -*- # 必须以root权限运行 import socket import sys import time import ...
- ios UITableView 搜索
自己实现 UITableView 搜索,相对于使用 UISearchDisplayController 来说自己写稍微麻烦了那么一点点,但是更加灵活.主要就是用一个字段区分出当前是搜索还是非搜索,然后 ...
- IBM Worklight OutOfMemoryError: Java heap space 错误
在启动 IBM Worklight 6.0 server 的时候,报了一个 OutOfMemory 的错误: [INFO ] FWLSE4006I: Worklight Studio is ...
- Vi/Vim命令壁纸图
下载地址 http://pan.baidu.com/s/1mtQdY