本博文基于知乎"JavaScript作用域问题?"一问,而引起了对JavaScript事件循环和单线程等概念与实践上的研究、深入理解。

一、概念
  0.关键词:JavaScript单线程事件循环(event loop)事件队列(event queue)执行栈(execution context stack)
  

  1.JavaScript引擎属于单线程作业所谓单线程,是指在JS引擎中负责解释和执行JavaScript代码的线程只有一个,也不妨叫它主线程。JavaScript引擎属于单线程作业,意味着:在同一时间只能执行一个代码块,这些代码块的执行就阻塞了异步事件的处理。[From JavaScript忍者秘籍]
  JavaScript的单线程,与它的用途有关。作为浏览器脚本语言,JavaScript的主要用途是与用户互动,以及操作DOM。这决定了它只能是单线程,否则会带来很复杂的同步问题。比如,假定JavaScript同时有两个线程,一个线程在某个DOM节点上添加内容,另一个线程删除了这个节点,这时浏览器应该以哪个线程为准?
    1.1 单线程意味着,【所有任务】都需要排队,前一个任务结束,才会执行后一个任务。如果前一个任务耗时很长,后一个任务就不得不一直等着。
    1.2 如果排队是因为计算量大,CPU忙不过来,倒也算了,但是很多时候CPU是闲着的,因为IO设备(输入输出设备)很慢(比如Ajax操作从网络读取数据),不得不等着结果出来,再往下执行。
    1.3 JavaScript语言的设计者意识到,这时主线程完全可以不管IO设备,挂起处于等待中的任务,先运行排在后面的任务。等到IO设备返回了结果,再回过头,把挂起的任务继续执行下去。
    1.4 于是,所有任务可以分成两种,一种是同步任务(synchronous),另一种是异步任务(asynchronous)。
    1.5 同步任务指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务;
    1.6 异步任务指的是,不进入主线程、而进入"任务队列"(task queue)的任务,只有"任务队列"通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行。
    1.7 具体来说,异步执行的运行机制如下。(同步执行也是如此,因为它可以被视为没有异步任务的异步执行。)
      (1)所有同步任务都在主线程上执行,形成一个执行栈(execution context stack)。
      (2)主线程之外,还存在一个"任务队列"(task queue)。只要异步任务有了运行结果,就在"任务队列"之中放置一个事件。
      (3)一旦"执行栈"中的所有同步任务执行完毕,系统就会读取"任务队列",看看里面有哪些事件。那些对应的异步任务,于是结束等待状态,进入执行栈,开始执行。
      (4)主线程不断重复上面的第三步。
    1.8 只要主线程空了,就会去读取"任务队列",这就是JavaScript的运行机制。这个过程会不断重复。
      [From 阮一峰老师:http://www.ruanyifeng.com/blog/2014/10/event-loop.html]

  2.事件循环(用于解决:异步问题/异步事件):在初期许多人会把异步理解成类似多线程的编程模式,其实他们中有着很大的差别,要完全理解异步,就需要了解 JS 的运行核心——事件循环(event loop)。
    2.1 事件循环:【事件队列】是一个存储着待执行任务的队列,其中的任务严格按照时间先后顺序执行,排在队头的任务将会率先执行,而排在队尾的任务会最后执行。事件队列每次仅执行一个任务,在该任务执行完毕之后,再执行下一个任务。【执行栈】则是一个类似于函数调用栈的运行容器,当执行栈为空时,JavaScript引擎便检查事件队列,如果不为空的话,事件队列便将第一个任务压入中运行。
  [From http://www.php.cn/js-tutorial-369771.html]
    2.2 常见异步任务:定时器任务(setTimeout();setInterval();)、Ajax事件浏览器/用户行为事件(例如:浏览器加载(load)、鼠标单击click、鼠标滑动/滑过/离开(mouseover、mouseout、mouseleave等)

二、分析

  由于JavaScript是单线程作业,当一个异步事件发生时(比如:鼠标单击、定时器触发甚至是XMLHttpRequest的完成事件),它就会排队,并且在线程空闲时才进行执行。且实际上,每个浏览器的排队机制是不同的。当我们设置一个延迟函数的时候,当前脚本并不会阻塞,它只是会在浏览器的事件表中进行记录,程序会继续向下执行。当延迟的时间结束之后,事件表会将回调函数添加至事件队列(task queue)中,事件队列拿到了任务过后便将任务压入执行栈(stack)当中,执行栈执行任务,执行console.log("after 1000 mills:",i);

for(var i = 0; i < 10; i++) {console.log("cur:",i);setTimeout(function() {console.log("after 1000 mills:",i); //当 console.log 被调用的时候,匿名函数保持对外部变量 i 的引用,此时for循环已经结束, i 的值被修改成了 10. }, 1000);
}

三、解决方案

  即时函数

    格式:(function(){ //...statement })(); 

for(var i = 0; i < 10; i++) {console.log("cur:",i),(function(i){setTimeout(function() {console.log("after 1000 mills:",i); }, 1000);})(i);//通过即时函数(1.创建函数实例,2.执行该函数,3.销毁该函数),将循环体异步事件压入执行栈中,立即执行的特性,以维护好变量当前的值
}

 

四、引用文献

  [JavaScript忍者秘籍]

  [JavaScript 运行机制详解:再谈Event Loop](http://www.ruanyifeng.com/blog/2014/10/event-loop.html)

  [为什么会有异步? 什么是事件队列?](http://www.php.cn/js-tutorial-369771.html)

转载于:https://www.cnblogs.com/johnnyzen/p/7894984.html

JavaScript之JS单线程|事件循环|事件队列|执行栈相关推荐

  1. 工作流 节点子线程_节点JS体系结构–单线程事件循环

    工作流 节点子线程 Today we will look into Node JS Architecture and Single Threaded Event Loop model. In our ...

  2. html5多线程例子,javascript的单线程事件循环及多线程介绍

    前言 其实我前面文章对于改变js的执行顺序及多线程都有相关介绍!例如,我们可以用setTimeout(fn,0)改变代码执行循序,文章最后也提及了Event Loop(事件循环).同时,js的Work ...

  3. 原生js循环展示dom_【前端面试】用一道题讲 js 的事件循环队列

    昨天去面了滴滴,一口气面了三面,考了 promise 和事件循环.之前的猿辅导也考察了这些,几乎所有的大厂中厂都一定会考原生 js 的事件循环队列. 今天,我把昨天考察的原题拿出来分析一下. setT ...

  4. js的事件循环机制:同步与异步任务(setTimeout,setInterval)宏任务,微任务(Promise,process.nextTick)...

    javascript是单线程,一切javascript版的"多线程"都是用单线程模拟出来的,通过事件循环(event loop)实现的异步. javascript事件循环 事件循环 ...

  5. javascript无限请求_JAVASCRIPT事件循环

    事件循环是用来理解JavaScript的最重要的方面之一.这篇文章旨在解释JavaScript如何与单个线程一起工作的细节,以及它如何处理异步函数. JavaScript代码运行是单线程.一次只执行一 ...

  6. JavaScript 如何工作的: 事件循环和异步编程的崛起 + 5 个关于如何使用 async/await 编写更好的技巧...

    原文地址:How JavaScript works: Event loop and the rise of Async programming + 5 ways to better coding wi ...

  7. [译] JavaScript 如何工作的: 事件循环和异步编程的崛起 + 5 个关于如何使用 async/await 编写更好的技巧...

    原文地址:How JavaScript works: Event loop and the rise of Async programming + 5 ways to better coding wi ...

  8. js的事件循环机制,同步和异步,以及宏任务与微任务的执行顺序

    前置知识点(重要): 1.什么是事件循环:js是单线程语言,同个时间执行一件事(同步),但是他可以有一个异步队列,遇到异步操作(比如说ajax这种阻塞时间很久的事情)把它们先放入异步队列,并且继续往下 ...

  9. JavaScript执行机制-node事件循环

    node环境下的事件循环机制 和浏览器有什么不同? 在node中,事件循环表现出来的状态和浏览器大致相同,但是node有一套自己的模型. node事件循环依靠libuv引擎,node选择chrome ...

  10. 【JavaScript】JS执行机制微任务和宏任务

    文章目录 一.了解JS执行机制 二. 异步任务(宏任务.微任务) 1.宏任务 2.微任务 三.实操演练 解析: 一.了解JS执行机制 在学习 promise(期约) 之前,我们需要了解JS的执行机制, ...

最新文章

  1. java rtmp_搭建rtmp直播流服务之2:使用java实现ffmpeg命令接口化调用(用java执行ffmpeg命令)...
  2. python的turtle画曲线_python的turtle模块画折线图
  3. 团队作业(四):描述设计
  4. 用于大型的科学计算的计算机,科学计算器广泛适用于大、中、小学生、教师、科研人员及其他各界...
  5. 用eslint + prettier + pre-commit管理项目(React)
  6. Rational Rose学习笔记02:创建用例图
  7. 怎么用html做随机颜色,JavaScript 实现网站标签随机颜色的方法
  8. PHPCMS整合UCENTER后登陆问题
  9. 华为发布了其自研的鸿蒙操作系统,官宣!鸿蒙手机操作系统即将发布
  10. sqlmap重要参数详解+用法,解决入门难题
  11. 2022年智能马桶行业发展趋势
  12. Python 爬取豆瓣电影Top250
  13. 任务栏右键工具栏里的语言栏没有的修复.reg
  14. 两场面试,一次心灵洗礼
  15. React新手入门学习
  16. java web安全框架_7.1 SpringSecurity安全框架
  17. 武林传奇之七剑下天山java游戏开发商_武林传奇2之七剑下天山的配方
  18. 公式不懂也无妨,业务精通才是真正的算法工程师
  19. MM物料账在制品承担差异功能及配置
  20. img固定宽高,图片等比缩小不变形

热门文章

  1. Affinity Publisher for Mac(桌面排版神器)中文版
  2. iOS开发之Xcode项目文件自动展开问题的解决办法
  3. 如何制作macOS Monterey启动U盘
  4. word更改字距调整,让文章更具美感!
  5. beaTunes5的关键词的检测分析
  6. Mac电脑很早以前就删除的信息,现在想要恢复该怎么做?
  7. 文本验证码被曝漏洞,淘宝、京东都中招!
  8. 探究JVM——运行时数据区
  9. 【转】测试用例设计——WEB通用测试用例
  10. UML设计的9种图例