先看一下下面这段js代码:

console.log('1');
setTimeout(function(){
console.log('2');
},0);
console.log('3');
请问打印的结果是什么?

这段代码看似很简单,但如果不了解JavaScript运行机制就很容易答错。正确的输出是:1 3 2

一、JavaScript运行机制

  想要弄懂javascript执行机制(运行机制),首先要了解关于js相关的知识点,如下:

  1、理解JavaScript是单线程的概念

    JavaScript语言的一大特点就是单线程,也就是说,同一个时间只能做一件事。JavaScript的单线程与它的用途有关。作为浏览器脚本语言,JavaScript的主要用途是与用户交互以及操作DOM。这就决定了它只能是单线程的,否则会带来复杂的同步问题。所以,为了避免复杂性,从一诞生开始JavaScript就是单线程,这已经成为了这门语言的核心特征,将来也不会变。

  2、 javaScript的同步任务和异步任务

    单线程就意味着,所有任务需要排队。前一个任务结束,才会执行后一个任务。如果前一个任务耗时很长,后一个任务就得一直等着。JavaScript语言的设计者认识到这个问题,将所有任务分成两种:一种是同步任务(synchronous),一种是异步任务(asynchronous)。

       同步任务指的是:在主线程上排队执行的任务,只有前一个任务执行完成,才能执行后一个任务。

     异步任务指的是:不进入主线程,而进入“任务队列(task queue)”的任务,只有"任务队列"通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行。

     异步任务包括:定时器、网络请求、Promise

     javaScript中同步任务和异步任务的执行机制流程如下(引用网上的一张图):

      

    1、所有同步任务都在主线程上执行,形成一个执行栈。

    2、异步任务进入Event Table并注册函数。当异步任务有了运行结果时,Event Table会将这个函数移入 Event Queue

    3、主线程中任务执行完毕为空,系统就会按次序的读取Event Queue中异步任务,进入执行栈,开始执行

    4、主线程不断重复上面的第三步。因为这个过程是循环不断的,所以又称为事件循环(Event Loop).

    3、javaScript的宏任务和微任务

      JavaScript的除了同步和异步任务外,对其任务还有更细的定义:宏任务(macro-task)和微任务(micro-task)。

      宏任务:包括整体代码script,setTimout,setInterval

      微任务:Promise,process.nextTick

      整体代码(宏任务)执行完后(即主线程执行栈为空),就开始事件循环(上面提到的Event Loop)。每次循环都要看Event Queue中是否有微任务,如果有则执行完所有的微任务后再执行其中一个宏任务,一个宏任务执行完成后开始进行下一次的循环。下一次循环开始先执行所有的微任务然后再执行其中一个宏任务。依次循环下去。

        javaScript中宏任务和微任务的执行机制流程如下:

        

    

四、异步任务有哪些?放入任务队列(或者事件队列)的时机

    任务分为宏任务(macro)和微任务(micro),在任务队列中的执行书序:微任务优先于宏任务

    异步微任务:

      1.ES6中的Promise

        放入任务队列的时机:异步操作成功(或者失败)后,将成功的回调函数(后者失败的回调函数)放入

        放入任务队列的任务:将成功的回调函数(后者失败的回调函数)放入任务队列中

        举例说明:

new Promise(function(resolve,reject){
resolve();
}).then(function(){
console.log('3')
});

      new Promise()立即执行,then回调函数 function(){console.log('3')} 放到Event Table中注册函数,当resolved()后,回调函数会放到微任务 Event Queue中,等待进入主线程执行

    异步宏任务:

      1.定时器(setTimeout和setInterval)

        放入Event Queue 时机:在规定时间到达后

        放入Event Queue 的任务:将回调函数放入宏事件队列中

        举例说明:     

setTimeout(fn,5000)

       fn进入Event Table,开始计时,等到5秒后回调函数进入Event Queue.当主线程代码为空时,就会读取Event Queue 中的回调函数,进入主线程开始执行。

      2.Ajax异步请求

        放入Event Queue的时机:在axjax加载完成时

        放入Event Queue 的任务: 将回调函数放入宏任务事件队列中

        举例说明:  

$.ajax({
url:'',
data:{},
success:function(){
console.log('发送成功')
}
})

        ajax进入Event Table,当ajax请求成功后,回调函数success进入Event Queue 。当主线程代码为空时,就会读取Event Queue 中的success回调函数,进入主线程开始执行。

      3.DOM事件

        放入Event Queue 的时机:在用户操作事件完成后

        放入Event Queue 的任务: 将回调函数放入宏任务事件队列中

        举例说明:

ele.on('click',fn,false);

         fn 进入Event Table,当触发click事件后,会将fn放入Event Queue中。

  五、分析下面代码,看看是否掌握了JS的执行机制

    例1:

    console.log('1');
setTimeout(function(){
console.log('2');
},1000);
new Promise(function(resolve){
console.log('3');
resolve();//Promise没有写resolve,then回调函数不会执行,为了测试直接执行
}).then(function(){
console.log('4');
})
console.log('5');

    分析:

      * 整体script作为第一个宏任务进入主线程,遇到console.log,输出1.

      * 遇到setTimeout, setTimeout是异步任务,被放到了event table 。1s 中中后,将其回调函数放到宏任务Event Queue 中。我们暂且记为setTimeout1

      *遇到Promise,  new Promise是同步任务,直接 输出3; .then里的函数是异步任务,被放到了event table。当执行resolve后将then回调函数放到微任务Event Queue。我们暂且记为then1

      * 遇到console.log('5'),直接 输出5

      * 到此主线程的任务执行完毕,第一轮事件循环宏任务结束。开始读取Event Queue中的事件,我们发现有一个微任务then1,所以先读取then1,输出4 。到此第一轮事件循环正式结束。

      *  第二轮事件循环从setTineout1开始, 输出2。第二轮事件循环结束。

      所以结果是:1 -> 3 -> 5 -> 4 -> 2 

    例2:

console.log('1');
setTimeout(function(){
console.log('2');
new Promise(function(resolve){
console.log('4');
resolve();
}).then(function(){
console.log('5');
})
}) new Promise(function(resolve){
console.log('7');
resolve();
}).then(function(){
console.log('8');
}) setTimeout(function(){
console.log('9');
new Promise(function(resolve){
console.log('11');
resolve();
}).then(function(){
console.log('12');
})
})
console.log('13');

    分析:

      1. 第一轮事件循环流程:

        * 整体script作为第一个宏任务进入主线程,遇到console.log('1'),直接输出1

        * 遇到setTimout,将其回调函数放到宏任务Event Queue中。我们暂且几位setTimeout1.

        * 遇到Promise。new Promise直接执行,输出7。then回调函数被放到微任务Event Queue中,我们暂且记为then1

        * 遇到setTimeout,将其回调函数放到宏任务Event Queue中。我们暂且记为setTimeout2

        * 遇到console.log('13'),直接输出 13

        * 到此第一轮事件循环宏任务结束。此时Event Queue中的任务情况: 宏任务: setTimeout1 setTimeout2;微任务:then1

        *  开始执行事件队列上的所有微任务,我们发现只有then1一个微任务,所以直接执行then1,输出8

        * 到此,第一轮事件循环正式结束。

      2. 第二轮事件循环流程:

        * 从事件队列中的宏任务setTimeout1开始执行,直接输出2

        * 遇到promise, new Promise直接执行,输出4。 then回调函数被放微任务Event Queue中,记为 then2

        * 到此第二轮事件循环宏任务结束。此时Event Queue中的情况: 宏任务:setTimeout2 ;微任务:then2

        *  开始执行event Queue中的所有微任务,发现只有then2一个微任务。直接执行,输出5

        * 到此,第二轮事件循环正式结束

      3. 第三轮事件循环流程:

        * 宏任务只剩下setTimeout2了,直接输出9.

        * 遇到promise ,new Promise 直接执行,输出11。 将then回调函数放到微任务Event Queue中,记为then3

        * 第三轮事件循环宏任务结束,开始执行微任务then3,输出 12

         * 第三轮事件循环结束

      3. 整段代码公鸡行了三次事件循环,输出:1 -> 7 -> 13 ->8 -> 2 ->4->5 -> 9 ->11->12

      

    

    

    

Javascript 运行机制的更多相关文章

  1. 深入理解JavaScript运行机制

    深入理解JavaScript运行机制 前言 本文是写作在给团队新人培训之际,所以其实本文的受众是对JavaScript的运行机制不了解或了解起来有困难的小伙伴.也就是说,其实真正的原理和本文阐述的并不 ...

  2. javascript运行机制

    太久没更新博客了,Javascript运行机制 Record it 1.代码块 JavaScript中的代码块是指由<script>标签分割的代码段.例如: <script type ...

  3. 从setTimeout谈JavaScript运行机制

    从setTimeout说起 众所周知,JavaScript是单线程的编程,什么是单线程,就是说同一时间JavaScript只能执行一段代码,如果这段代码要执行很长时间,那么之后的代码只能尽情地等待它执 ...

  4. JavaScript运行机制详解

    JavaScript运行机制详解   var test = function(){ alert("test"); } var test2 = function(){ alert(& ...

  5. 深入浅出JavaScript运行机制

    一.引子 本文介绍JavaScript运行机制,这一部分比较抽象,我们先从一道面试题入手: console.log(1); setTimeout(function(){ console.log(3); ...

  6. javascript 运行机制 事件循环 浏览器缓存 (慕课网 前段跳槽面试必备 4-1,4-2,4-3)

    4-1 渲染机制:-1-,什么是DOCTYPE及其作用?DTD(document type definition,文档类型定义)是一系列的语法规则,用来定义XML或(X)HTML的文件类型,浏览器会使 ...

  7. JavaScript运行机制与setTimeout

    前段时间,老板交给了我一个任务:通过setTimeout来延后网站某些复杂资源的请求.正好借此机会,将JavaScript运行机制和setTimeout重新认真思考一遍,并将我对它们的理解整理如下. ...

  8. JavaScript 运行机制 & EventLoop

    JavaScript 运行机制 & EventLoop 看阮老师博客和自己的理解,记录的学习笔记,js的单线程和 事件EventLoop 机制. 1. JavaScript是单线程 JavaS ...

  9. JavaScript 运行机制详解:再谈Event Loop

    原文地址:http://www.ruanyifeng.com/blog/2014/10/event-loop.html 一年前,我写了一篇<什么是 Event Loop?>,谈了我对Eve ...

随机推荐

  1. jquery 定位

    jquery 定位 <html> <head> <title>jquery 定位</title> </head> <body> ...

  2. No-6.用户权限相关命令

    用户权限相关命令 目标 用户 和 权限 的基本概念 用户管理 终端命令 组管理 终端命令 修改权限 终端命令 01. 用户 和 权限 的基本概念 1.1 基本概念 用户 是 Linux 系统工作中重要 ...

  3. ios之UITextfield (2)

    UItextField通常用于外部数据输入,以实现人机交互.下面以一个简单的登陆界面来讲解UItextField的详细使用. //用来显示“用户名”的label UILabel* label1 = [ ...

  4. 如何用纯 CSS 创作文本滑动特效的 UI 界面

    效果预览 在线演示 按下右侧的"点击预览"按钮可以在当前页面预览,点击链接可以全屏预览. https://codepen.io/comehope/pen/QrxxaW 可交互视频教 ...

  5. CSS3---渲染属性

    1.计数器 CSS3计数器( CSS Counters )可以允许我们使用css对页面中的任意元素进行计数,实现类似于有序列表的功能.与有序列表相比,它的突出特性在于可以对任意元素计数,同时实现个性化 ...

  6. Servlet+JSP教程之:第一个Web程序

    我们知道当浏览器发送请求给服务器后,服务器会调用并执行对应的逻辑代码进行请求处理.逻辑代 码是由程序员自己编写然后放进服务器进行运行,其实就是Servlet程序. 第一个Web程序: 开发工具: My ...

  7. JQuery中如何查找某种类型的所有元素&选择器

    更多的是,有关于选择器的内容. 背景:查找某控件中所有的input元素,代码如下: $("#div1").find("input").each(function ...

  8. Android开发——使用ADB Shell命令实现模拟点击(支付宝自动转账实现)

    首先声明,本人反对一切利用技术的违法行为 本文的实现代码已经销毁,本文以介绍流程为主 1.这里所说的模拟点击不是在自己的APP里点击,点自己APP上的控件没什么好说的 不仅是支付宝转账,其他的获取别人 ...

  9. Python的3种格式化字符串方法

    Python中有3种format字符串的方式: 传统C语言式 命名参数 位置参数 1. 传统C语言式 和c语言里面的 sprintf 类似,参数格式也一样 title = "world&qu ...

  10. [Go]条件语句

    package main import ( "io/ioutil" "fmt" ) //条件语句 //if的条件语句不需要括号 //if的条件里可以赋值,if的 ...