浅谈JS运行机制

首先放上2年前自己对js单线程的理解的博客:JS为什么是单线程的?JS的同步异步
虽然说题目是这样写,但是只是浅显的说了一嘴同步异步的事情,并没有涉及到宏任务微任务等更深层次的理解。宏任务微任务其实在开发学习过程中都有接触过,但是并没有完全的把这些知识串联起来。
就js的循环事件也有对比node进行了一篇文章的分享,也是浅浅之谈。js和node.js的循环事件

写这个的起因,在笔记上写上了:JS执行后进先出的执行规则,想把整个js运行整理梳理一遍

所以看阮大师的文章,自己顺一遍整个知识,按照自己的理解在反述一遍。

1.JS是单线程:为什么是单线程

单线程:同一个时间只能做一件事。
作为浏览器脚本语言,JS的主要用途是与用户互动,以及操作DOM。这一功能就决定了他只能是单线程的。
单线程就意味着:所有的任务都要排队。前一个任务执行结束后才能执行后一个任务。

2.任务队列

因为js是单线程,所以所有的任务累加起来就要排队。所有的任务可以分为两种:同步任务、异步任务。
同步任务:在主线程上排队执行的任务。
异步任务:不进入主线程,进入任务队列的任务,
在这里插入图片描述
所谓的回调函数,就是异步任务在任务队列里执行完毕后,主线程执行完毕同步任务,开始执行任务队列中的异步任务时,执行的函数,就是回调函数。

所谓"回调函数"(callback),就是那些会被主线程挂起来的代码。异步任务必须指定回调函数,当主线程开始执行异步任务,就是执行对应的回调函数。

"任务队列"是一个先进先出的数据结构,排在前面的事件,优先被主线程读取。主线程的读取过程基本上是自动的,只要执行栈一清空,"任务队列"上第一位的事件就自动进入主线程。但是,由于存在后文提到的"定时器"功能,主线程首先要检查一下执行时间,某些事件只有到了规定的时间,才能返回主线程。

3.Event Loop

主线程从"任务队列"中读取事件,这个过程是循环不断的,所以整个的这种运行机制又称为Event Loop(事件循环)。
在这里插入图片描述
上图就是event loop的执行示意图
首先把异步请求放入栈中,在js主线程执行完堆中的同步请求后,开始执行栈中的异步请求(调用了各种外部API),执行完毕后,主线程就会去读取任务队列去执行那些事件对应的回调函数。

可能看图比较抽象,阮大神有一个例子看得更直白一点:
在这里插入图片描述

然后回归问题:
笔记本上写入js执行是后进先出

其实是数据结构和算法的问题,但是同样js是可以实现

先进先出 - 队列效果(后面的数据把前面的数据往前顶)

var arr = new Array();
arr.unshift(1);
arr.unshift(2);
arr.unshift(3);
arr.unshift(4);
// 此时数组arr= [4, 3, 2, 1]
arr.pop() //把最后一位移出来
//此时arr = [4, 3, 2],达到先进来的数据为1,先出去为1

先进先出:unshift + pop 组合

先进后出 - 堆栈效果(后面进来的数据先出去)

var arr = new Array();
arr.push(1);
arr.push(2);
arr.push(3);
arr.push(4);
// 此时arr =  [1, 2, 3, 4]
arr.pop() 
// 此时arr = [1, 2, 3]
// 达到先进后出的效果, 1最早进来,最后出去

先进后出: push + pop组合

2021年12月更新----本次拓展 宏任务和微任务
宏任务和微任务都是异步的任务。都是等待脚本的同步代码执行完毕后,在任务队列中去执行。
首先看下宏任务和微任务分别都有哪些

在这里插入图片描述

先说一个定时器的例子

setTimeout(() => {
    
    
   console.log('a');
}, 10000);

setTimeout(() => {
    
    
   console.log('b');
}, 100);

在实际进行时,先console出来b,再出来a。
从任务队列的角度去看执行的过程=》 首先执行b,等待到10秒后,a才会被推入宏任务队列中执行。

猜你喜欢

转载自blog.csdn.net/weixin_40121676/article/details/117435902