今天面试的时候被问到一个问题,是关于 JS 异步的。当时我脑海中闪过了一个单线程的概念,但却没有把真正的原理阐述清楚。所以回来特意重新回顾了前面单线程和异步相关的一些知识点。

虽然之前学习的时候也接触了单线程模型相关的东西,但当时理解得并不是很清楚和明白。所以这道面试题也没有给出一语中的的答案。重新阅读阮一峰的 《JavaScript 运行机制详解》和我之前写的《setTimeout 异步与回调》之后。我决定重新写一篇博客来更加白话的总结 JS 的单线程机制和异步。

重演历史 - 为什么 JS 是单线程

当我们打开一个页面,页面的 JS 会去执行。从系统层面来说,他是单线程的去执行。换句话讲系统中只有一个线程去处理整个页面的渲染(代码的执行)。为什么会这样呢?因为简单,因为 JS 很早就被发明出来了,浏览器也是。那个时候考虑的第一件事,是功能简单。试想一下如果是多线程,一个处理页面渲染 DOM 操作,另外的线程也处理,就会出现混乱。因为搞不清楚谁做了什么,做到什么程度了。但如果只有一个线程单独处理这些操作,就非常好的能够管控。所以浏览器的模型就是单线程。

HTML5 提出 Web Worker 标准,允许 JavaScript 脚本创建多个线程,但是子线程完全受主线程控制,且不得操作 DOM。所以,这个新标准并没有改变 JavaScript单线程的本质。

所以在早期,当使用大量同步的代码时,打开网页就会出现卡屏、卡页面的情况。因为在获取数据的时候,使用同步的代码,后面的数据还没到来之前,获取数据之后的代码都无法执行。只有等获取数据全部结束后,才会执行下面的代码。

所以后来,大家都知道了。开始使用异步。

同步队列 / 任务队列

既然是单线程,就意味着需要排队,即前面的任务结束,后面的任务才能执行。所以所有的任务被分成了两种,一种是同步任务,一种就是异步任务。同步任务指的就是在主线程上排队执行的任务,只有前一个任务执行完毕,才能继续执行后一个任务。而异步任务指的是,不进入主线程(同步队列 stack),而是进入任务队列(task queue)的任务。只有任务队列通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行。

只要主线程空了,就会去读取 "任务队列" ,这就是 JavaScript 的运行机制。这个过程会不断重复。

重新理解这张图

例如我们有一段代码,这些代码是用来做一些操作。正常情况下,代码都是放置在栈(stack)中的,正常执行的时候是一个个去执行的。但是有些时候,比如给页面元素绑定一个事件,发了一条 ajax 请求,或者还有一些异步处理。这个时候,就不能够放置在 stack 中了。不然就会处于长久的等待之中,其他的代码就无法按顺序即使的执行。

所以在浏览器里面,还有一个可以被称之为任务队列的地方。对于一些异步的任务,都是放到任务队列里面。举例来说,当用户给一个元素绑定事件 onClick,绑定事件的操作在 stack 执行,但 onClick 回调本身是放到任务队列里面的。

 

重新理解 setTimeout

之前认识 setTimeout 时,就已经见过这段代码了,他的输出结果是先输出 2,后才输出 1。原理也是因为单线程机制。

setTimeout(function(){
console.log(1)
},0) console.log(2)

即 console.log(2) 被放入到 stack 中执行,setTimeout() 被放入到 callback queue了。换句话说,必须要等所有 stack 中的同步的代码全都执行完后,才会去执行异步的事件。所以不管 setTimeout() 里面的时间是 0 还是 1000 都会被排到后面。

所以下面这个例子,1 永远不会被输出,且 2 被循环多次后,会被卡死。因为永远都在执行 console.log(2) 这个同步代码。而整个 stack 栈都被堵死了。 setTimeout() 根本没办法执行。

var isOk = true
setTimeout(function(){
console.log(1)
isOk = false
},1000) while(isOk){
console.log(2)
}

分析原生 Ajax

所以再去分析原生 Ajax 里面的代码,也能够更好的理解同步任务和异步任务。

 

这次,我想我真的理解了 JavaScript 的单线程机制。

博客园大佬比较多...  由于本人水平有限。如果这篇博文中一些地方有错误,或者各位大佬觉得我还是没有理解单线程机制和异步,请轻喷...

我想这次我真的理解了 JavaScript 的单线程机制的更多相关文章

  1. Javascript:再论Javascript的单线程机制 之 DOM渲染时机

    Javascript:再论Javascript的单线程机制 之 DOM渲染时机 背景 Javascript是单线程事件驱动的,所有能看到的Javascript代码都是在一个线程执行,定时器回调和AJA ...

  2. Javascript引擎单线程机制及setTimeout执行原理说明

    setTimeout用法在实际项目中还是会时常遇到.比如浏览器会聪明的等到一个函数堆栈结束后才改变DOM,如果再这个函数堆栈中把页面背景先从白色设为红色,再设回白色,那么浏览器会认为DOM没有发生任何 ...

  3. JavaScript的异步机制

    我们经常说JS是单线程的,比如node.js研讨会上大家都说JS的特色之一是单线程的,这样使JS更简单明了,可是大家真的理解所谓JS的单线程机制吗?单线程时,基于事件的异步机制又该当如何 1 先看下两 ...

  4. 我理解的javascript单线程机制

    废话不多说,我们先来看几个例子: 1. setTimeout( console.log(2); result:  2 1   2.   console.log(100 setTimeout( cons ...

  5. Javascript是单线程的深入分析

    本来想总结一下的,网上却发现有人已经解释的很清楚了,特转过来. 这也解释了为什么在用自动化测试工具来运行dumrendtree时设定的超时和测试case设定的超时的关联性. 面试的时候发现99%的童鞋 ...

  6. 简述JavaScript的运行机制

    想要理解JavaScript的运行机制,需要分别深刻理解以下几个点: · JavaScript的单线程机制 · 任务队列(同步任务和异步任务) · 事件和回调函数 · 定时器 · Event Loop ...

  7. 您真的理解了SQLSERVER的日志链了吗?

    您真的理解了SQLSERVER的日志链了吗? 先感谢宋沄剑给本人指点迷津,还有郭忠辉童鞋今天在QQ群里抛出的问题 这个问题跟宋沄剑讨论了三天,再次感谢宋沄剑 一直以来,SQLSERVER提供了一个非常 ...

  8. Javascript事件模型系列(四)我所理解的javascript自定义事件

    被我拖延了将近一个月的javascript事件模型系列终于迎来了第四篇,也是我计划中的最后一篇,说来太惭愧了,本来计划一到两个星期写完的,谁知中间遇到了很多事情,公司的个人的,搞的自己心烦意乱浮躁了一 ...

  9. 理解的javascript自定义事件

    理解的javascript自定义事件 被我拖延了将近一个月的javascript事件模型系列终于迎来了第四篇,也是我计划中的最后一篇,说来太惭愧了,本来计划一到两个星期写完的,谁知中间遇到了很多事情, ...

随机推荐

  1. 解决dpdk中出现IOMMU not found的问题

    问题 在使用VFIO前,需要在BIOS打开VT-x和VT-d,想把一个PCIe网卡透传到虚拟机中,发现虚拟机启动失败,提示IOMMU没有找到. 输入以下命令确定vt-d开启 dmesg | grep ...

  2. webapi中的模型验证

    mic: https://docs.microsoft.com/en-us/aspnet/web-api/overview/formats-and-model-binding/model-valida ...

  3. 1<=portNo<=4竟然在keil4.71里面不报错

    1.if( 1<=portNo<=4 ) {  CardIn2_CS_L; //pull low  CardIn1_CS_H;  CardOut1_CS_H;  CardOut2_CS_H ...

  4. zookeeper启动时报错:Error contacting service. It is probably not running问题

    查看zookeeper.out发现启动日志报错未找到java路径. 启动日志位于zookeeper-4.0.10/bin目录下 修改/etc/profile中环境变量得以解决.

  5. uboot中ftd命令

    可以从u-boot官网源码下载一个比较新的u-boot, 查看它的cmd/fdt.cftp://ftp.denx.de/pub/u-boot/ fdt命令使用示例nand read.jffs2 320 ...

  6. i2c子系统

    linux内核的I2C驱动框架总览(1)I2C驱动框架的主要目标是:让驱动开发者可以在内核中方便的添加自己的I2C设备的驱动程序,从而可以更容易的在linux下驱动自己的I2C接口硬件(2)源码中I2 ...

  7. SVN搭建(linux 7)

    第一步:通过yum命令安装svnserve,命令如下: >yum -y install subversion 此命令会全自动安装svn服务器相关服务和依赖,安装完成会自动停止命令运行 若需查看s ...

  8. VB

    on error resume next: 从该语句开始,遇到错误时程序不会中止,也不会出现错误提示,将继续运行.作用范围直至程序结束或语句所在函数等结束 Public Property :可读也可写 ...

  9. C++程序设计入门(上) string类的基本用法

    string类中的函数 1. 构造 2. 追加 3. 赋值 4. 位置与清除 5. 长度与容量 6. 比较 7. 子串 8. 搜索 9. 运算符 追加字符串 string s1("Welc ...

  10. swiper 仿淘宝详情页面 视频图片切换

    1.好兄弟,看一下是否是你需要的 2.废话不多说 直接上代码,复制粘贴一下 自己引用一下swiper.js和css 然后就可以开始玩儿了 <!DOCTYPE html> <html& ...