Web前端JavaScript学习--总结 JavaScript 运行机制解析
小职 2021-09-02 来源 : 阅读 403 评论 0

摘要:本文主要介绍了Web前端JavaScript学习--总结 JavaScript 运行机制解析,通过具体的内容向大家展现,希望对大家前端开发Javascript的学习有所帮助。

本文主要介绍了Web前端JavaScript学习--总结 JavaScript 运行机制解析,通过具体的内容向大家展现,希望对大家前端开发Javascript的学习有所帮助。

Web前端JavaScript学习--总结 JavaScript 运行机制解析

引言

在一些面试中,我们或许会被问到这样的问题


简述一下 JavaScript 的运行机制?


还有可能会被问这样的代码


setTimeout(function () {

    console.log('定时器开始啦')

});


new Promise(function (resolve) {

    console.log('马上执行for循环啦');

    for (var i = 0; i < 10000; i++) {

        i == 99 && resolve();

    }

}).then(function () {

    console.log('执行then函数啦')

});


这些虽然看起来很深奥很复杂,但是如果你了解了 JavaScript 的运行机制,这些问题都能够一一化解


先附上本文的纲要,本文将会从这三个方面去解析 JavaScript 的运行机制


Web前端JavaScript学习--总结 JavaScript 运行机制解析


首先我们来谈谈 JavaScript 的单线程


1. 为什么是单线程?

众所周知,JavaScript 是一门单线程的语言,也因此带来了很多诟病,那么单线程如此不堪,为什么不把它设计成多线程的呢?


其实这个问题就出现在了 JavaScript 的应用场景上,我们通常采用 JavaScript 来操作 DOM 元素,这在现在来看没什么问题。但是我们想一想,如果 JavaScript 变成了一门多线程的语言,那会发生什么呢?


想象一下下面的场景


一段 JS 代码删除 DOM 元素,一段 JS 代码更改 DOM 元素样式,它们一起被执行了,这会发生什么?


先别说浏览器该怎么处理了,我都不知道该如何处理,那浏览器就会崩溃掉 …


为了避免这样的情况, JavaScript 被设计成了一门单线程的语言


单线程就意味着,一次只能执行一个任务,其他任务都需要排队等待


但是为了能有多线程的功能,有了很多的尝试


在 HTML5 中提出了 web worker 标准,它提供了一套完整的 API 去允许在主线程以外去执行另一个线程,但是这不意味着 JavaScript 从此拥有了多线程的能力,同时我们也不能用它来操作 DOM 元素。


在 JavaScript 中还有着独特执行机制,它将主线程中的任务分为同步任务和异步任务


2. 为什么需要异步?

为了能够解决单线程带来的代码阻塞等问题


JS 是单线程的,我们可以想象成有一个售票窗口,有很多人在窗口排队办理业务,而 JS 只能一个一个处理,那如果有一个客户的需求很多,办理业务的时间很长,那么这条队伍的其他人就只能干等着了,就相当于代码阻塞了,也就是浏览器假死,等待代码执行


因此有了同步任务和异步任务的概念


就是需要通过这样来区分,将那些办理业务时间长的分出来,等到其他客户处理完毕之后再统一处理


关于同步任务和异步任务是这样解释的


同步任务:是在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务,例如:console.log

异步任务:不进入主线程、通过事件循环机制处理,在任务队列中注册回调函数最终拿到结果,例如:setTimeout

了解了什么是同步,什么是异步,我们来一道非常简单的题目


console.log(1);

setTimeout(()=>{console.log(2);},0)

console.log(3);


结果输出 1 3 2


原因是 setTimeout 是异步任务,需要在同步代码执行之后再执行


接下来我们聊聊运行机制的核心:事件循环


3. 事件循环

首先我们用一张图来理解事件循环

Web前端JavaScript学习--总结 JavaScript 运行机制解析



它的运行机制如下:


所有同步任务在主线程上执行,形成一个执行栈,也就是上图蓝色箭头表示

主线程以外有一个异步任务队列(红色箭头),会等到异步任务返回结果后将它放入任务队列

当主线程中执行栈代码执行完毕,也就是同步任务执行完毕,就会开始读取任务队列代码,再放入执行栈中执行

不断地重复上面三步,这就是事件循环

用图形来描绘的话,就是上图中的三个黑色箭头,连成的闭环


也就是说:只要主线程执行栈空了,就会去读取任务队列,这个过程是循环不断的,这种运行机制就叫做事件循环


了解了事件循环,我们对前面那题做一个简单的升级


console.log(1);

setTimeout(()=>{console.log(2);},0)

setTimeout(()=>{console.log(3);},1000)

setTimeout(()=>{console.log(4);},0)

console.log(5);


这次输出了 1 – 5 – 2 – 4 – 3


可能会有人会对 3 的输出有疑惑,首先定时器都是异步任务,会先被放入异步任务队列当中,需要等待异步任务返回结果后,再将回调函数放入任务队列当中,等待主线程来执行,因此,2 和 4 会在 3 之前输出


4. 异步任务队列细节

常见的会放入异步任务队列的事件


DOM 事件

Promise

Ajax 请求

setTimeout 和 setlnterval

文件上传

至于加入异步任务队列的时间,是需要根据当前异步任务而定的,不是说拿到异步任务直接添加到任务队列里面,是要等到当前异步任务执行完成返回结果,才将其放到任务队列里


就拿 setTimeout 来说,是需要等待定时结束再将回调加入任务队列的


也可以结合下图理解

Web前端JavaScript学习--总结 JavaScript 运行机制解析



了解了任务队列,我们需要再谈一谈异步任务当中,又被细分出来的宏任务和微任务


5. 宏任务和微任务

宏任务队列可以有多个,微任务队列只有一个


那么什么是宏任务,什么是微任务呢?


宏任务有:HTML解析、鼠标事件、键盘事件、网络请求、执行主线程js代码和定时器

微任务有:promise.then,DOM 渲染,async,process.nextTick

那它是怎么被执行的呢?


当执行栈中的同步任务执行完毕后,先执行微任务


微任务队列执行完毕后,会读取宏任务


执行宏任务的过程中,遇到微任务,再加入微任务队列


宏任务执行完后,再次读取微任务队列,依次循环


画个图来辅助理解一下


用一句简单的话来总结:微任务永远在宏任务执行之前被执行完毕


Web前端JavaScript学习--总结 JavaScript 运行机制解析


特别注意的是:由于代码的入口就是一个 script 标签。因此,全局任务属于宏任务


6. 实战

在了解了这么多后,我们来看一到经典的面试题


console.log("1");

setTimeout(function () {

    console.log("2");

    new Promise(function (resolve) {

        console.log("3");

        resolve();

    }).then(function () {

        console.log("4");

    });

});

new Promise(function (resolve) {

    console.log("5");

    resolve();

}).then(function () {

    console.log("6");

});

setTimeout(function () {

    console.log("7");

});

setTimeout(function () {

    console.log("8");

    new Promise(function (resolve) {

        console.log("9");

        resolve();

    }).then(function () {

        console.log("10");

    });

});

new Promise(function (resolve) {

    console.log("11");

    resolve();

}).then(function () {

    console.log("12");

});

console.log("13");


答案是:1 – 5 – 11 – 13 – 6 – 12 – 2 – 3 – 4 – 7 – 8 – 9 – 10


第一轮循环


从全局任务入口,首先打印日志 1

遇到宏任务 setTimeout ,交给异步处理模块,记为setTimeout1

再遇到 promise 对象,打印日志 5 ,将 promise.then 加入微任务队列,记做 p1

又遇到 setTimeout 交给异步处理模块,记为 setTimeout2

又遇到 setTimeout 交给异步处理模块,记为 setTimeout3

遇到 promise 对象,打印日志 11 ,将 promise.then 加入微任务队列,记做 p2

遇到打印语句,直接打印日志 13

本轮循环共打印:1 – 5 – 11 – 13


当前循环结果

Web前端JavaScript学习--总结 JavaScript 运行机制解析



第二轮循环


首先执行微任务队列 p1 和 p2 ,先进先出,先打印 6 再打印 12

微任务事件处理完毕,开始执行宏任务 setTimeout1

遇到打印语句,直接打印日志 2

又遇到 promise 对象,打印日志 3,将 promise.then 加入微任务队列,记做 p3

第二轮循环结束


当前运行图为

Web前端JavaScript学习--总结 JavaScript 运行机制解析



第三轮循环


首先执行微任务队列,打印日志 4

微任务处理完毕,执行宏任务 setTimeout2

遇到打印语句,直接输出 7

本轮循环结束

Web前端JavaScript学习--总结 JavaScript 运行机制解析



第四轮循环


微任务队列为空,执行宏任务 setTimeout3

遇到打印语句,打印日志 8

遇到 promise 对象,执行打印语句,打印 9

将 promise.then 加入微任务队列 记做 p4

Web前端JavaScript学习--总结 JavaScript 运行机制解析


第五轮循环


首先清空微任务队列,执行打印语句,打印 10

执行完毕

以上就是关于 JavaScript 运行机制的全部内容,希望能有所收获


我是小职,记得找我

✅ 解锁高薪工作

✅ 免费获取基础课程·答疑解惑·职业测评

Web前端JavaScript学习--总结 JavaScript 运行机制解析

本文由 @小职 发布于职坐标。未经许可,禁止转载。
喜欢 | 0 不喜欢 | 0
看完这篇文章有何感觉?已经有0人表态,0%的人喜欢 快给朋友分享吧~
评论(0)
后参与评论

您输入的评论内容中包含违禁敏感词

我知道了

助您圆梦职场 匹配合适岗位
验证码手机号,获得海同独家IT培训资料
选择就业方向:
人工智能物联网
大数据开发/分析
人工智能Python
Java全栈开发
WEB前端+H5

请输入正确的手机号码

请输入正确的验证码

获取验证码

您今天的短信下发次数太多了,明天再试试吧!

提交

我们会在第一时间安排职业规划师联系您!

您也可以联系我们的职业规划师咨询:

小职老师的微信号:z_zhizuobiao
小职老师的微信号:z_zhizuobiao

版权所有 职坐标-一站式IT培训就业服务领导者 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
 沪公网安备 31011502005948号    

©2015 www.zhizuobiao.com All Rights Reserved

208小时内训课程