JS执行机制

JS执行机制

setTimeout中的回调函数一定会准时执行吗?

const start = Date.now()
setTimeout(()=>{
    const end = Date.now()
    console.log(end-start)
}, 500)

// async function delay(num){
//     if(num>100000) return
//     await Promise.resolve().then(()=>delay(++num))
// }

// delay(1)
进程与线程
什么是进程?
  • 进程是系统进行资源分配的基本单位
  • 进程是程序的基本执行实体,可以理解为一个可以独立运行且拥有自己资源空间的任务程序
  • 进程之间相互隔离,互不干扰
什么是线程?
  • 线程是任务调度和执行的基本单位
  • 一个进程中可以并发多个线程,每个线程并行执行不同的任务
  • 同一进程下的线程之间可以直接通信和共享数据
单线程、多线程与多进程

单线程:是指程序中仅包含一个执行流,程序将会按照执行流顺序执行。

多线程:是指程序中包含多个执行流,即在一个程序中可以同时运行多个不同的线程来执行不同的任务,也就是说允许单个程序创建多个并行执行的线程来完成各自的任务

多进程:多个拥有自身资源空间且能独立运行的任务程序

举个栗子

单线程、多线程、多进程

JS单线程

所谓单线程,是指在JS引擎中负责解释和执行JavaScript代码的线程只有一个。

JS为什么是单线程?

JS的单线程,与它的用途有关。作为浏览器脚本语言,JavaScript的主要用途是与用户交互,以及操作DOM。假如JavaScript同时有两个线程,一个线程在某个DOM节点上添加内容,另一个线程删除了这个节点,这时浏览器应该以哪个线程为准?

JS如何处理延时任务?

既然JS是单线程的,那么在同一时间应该只能执行一个任务。假如当前存在一个任务需要等待五秒后才能拿到结果输出,那么JS会等待五秒后再执行后续任务吗?显然不会。

同步与异步
同步:

指的是代码当中的任务将会按照代码编写顺序依次执行,后一个任务必须等待前一个任务执行完毕才会执行。

​ 例如,银行服务窗口

异步:

指代码执行过程中,不会等待一个任务执行完成再执行另一个任务,异步任务开启过后就立即往后执行下一个任务,耗时任务的后续逻辑一般会通过回调函数的方式定义,当耗时任务完成后再执行回调函数。

浏览器中的进程与线程
浏览器中主要包括哪些进程?

浏览器主进程:

负责控制浏览器除标签页外的界面,包括地址栏、书签、前进后退按钮等,以及负责与其他进程的协调工作

GPU进程:

​ 负责整个浏览器界面的渲染,在 浏览器显示 GPU 加速内容时使用的进程。 浏览器会用 GPU 来加速网页渲染、典型的 HTML、CSS 和图形元素。

插件进程:

​ 主要负责插件的运行,因为插件可能崩溃,所以需要通过插件进程来隔离,以保证插件崩溃也不会对浏览器和页面造成影响

网络进程:

​ 主要负责页面的网络资源加载,之前是作为一个模块运行在浏览器主进程里面,后续独立出来,成为一个单独的进程

渲染进程(浏览器内核):

​ 负责控制显示tab标签页内的所有内容,核心任务是将HTML、CSS、JS转为用户可以与之交互的网页,排版引擎Blink和JS引擎V8都是运行在该进程中,默认情况下Chrome会为每个Tab标签页创建一个渲染进程

渲染进程
GUI渲染线程:

​ 负责渲染页面,解析html和CSS、构建DOM树、CSSOM树、渲染树、和绘制页面,重绘重排也是在该线程执行

JS引擎线程:

​ 负责解析和执行Javascript脚本程序。

注意:GUI渲染线程与JS引擎线程是互斥的,js引擎线程会阻塞GUI渲染线程。

事件触发线程:

​ 主要用来控制事件循环,比如JS执行遇到计时器,AJAX异步请求等,就会将对应任务添加到事件触发线程中,在对应事件符合触发条件触发时,就把事件添加到待处理队列的队尾,等JS引擎处理

定时器线程:

​ 因为JS引擎是单线程的,所以如果处于阻塞状态,那么计时器就会不准了,所以需要单独的线程来负责计时器工作

异步HTTP请求线程:

​ XMLHttpRequest连接后浏览器开的一个线程,比如请求有回调函数,异步线程就会将回调函数加入事件队列,等待JS引擎空闲执行

宏任务与微任务

在JavaScript中,事件队列中的任务被分为两种:宏任务(Macrotask)和微任务(Microtask),他们分别会被添加到宏任务队列和微任务队列。

为什么要区分宏任务和微任务?

​ 这种设计是为了给紧急任务一个插队的机会,否则新入队的任务永远被放在队尾。区分了宏任务和微任务后,本轮循环中的微任务实际上就是在插队,这样微任务中所做的状态修改,在下一轮事件循环中也能得到同步。例如,银行大爷办理额外业务

宏任务:

  • Script(整体代码)

  • setTimeout

  • setInterval

  • setImmediate(用来把一些需要长时间运行的操作放在一个回调函数里,在浏览器完成后面的其他语句后,就立刻执行这个回调函数,类似setTimeout(fn,0)—已废弃)

  • I/O操作

  • UI渲染

微任务:

  • Promise.then、.catch、.finally
  • async/await
  • MutationObserver(html5新特性,监听DOM树结构改变,作出相应处理)
  • process.nextTick(Node)
  • queueMicrotask
事件循环机制

概述:

由于js执行引擎只有一个主线程执行代码逻辑,遇到需要异步执行的任务代码,会将其添加到事件队列中,等待主线程空闲时执行。

事件队列中的任务分为宏任务和微任务,他们会被添加到不同的事件队列中(宏/微任务队列)。

当主线程将同步代码执行完毕后,会先将其产生的的微任务推入主线程执行,如果微任务执行过程中又产生了新的微任务,新产生的微任务会被添加到微任务队列末尾,按照队列先进先出原则继续执行。当微任务队列被清空后,会执行下一个宏任务,再清空宏任务产生的微任务,不断循环。

警告: 因为微任务自身可以入列更多的微任务,且事件循环会持续处理微任务直至队列为空,那么就存在一种使得事件循环无尽处理微任务的真实风险。如何处理递归增加微任务是要谨慎而行的。 ------MDN

图解:

JavaScript整体代码在执行中按顺序从上往下编译执行
在这里插入图片描述

执行同步代码,遇到异步任务将其添加到宏微任务队列
在这里插入图片描述

执行栈中的代码执行完毕,执行栈处于空闲状态,先将微任务队列清空

微任务执行过程中,产生新的微任务,添加到队列末尾
在这里插入图片描述

清空微任务队列
在这里插入图片描述

执行下一个宏任务,将产生的微任务添加到微任务队列
在这里插入图片描述

宏任务执行完毕,清空微任务队列
在这里插入图片描述

执行下一个宏任务,任务队列全部清空,结束
在这里插入图片描述

练习:

Test1:

console.log('start');

setTimeout(() => {
  console.log('T1');
  new Promise(resolve => {
    console.log('P1');
    resolve();
  })
    .then(() => {
      console.log('P1-then');
    })
}, 0);

new Promise(resolve => {
  console.log('P2');
  resolve();
})
  .then(() => console.log('P2-then'));

console.log('end');
// start
// P2
// end
// P2-then
// T1
// P1
// P1-then

Test2:

console.log(1)
setTimeout(() => {
  console.log(4)
  new Promise(resolve => {
    console.log(5)
    resolve()
  })
    .then(() => console.log(6))
}, 0)
new Promise(resolve => {
  console.log(2)
  resolve()
})
  .then(() => console.log(3))
setTimeout(() => {
  console.log(7)
  new Promise(resolve => {
    console.log(8)
    resolve()
  })
    .then(() => console.log(9))
}, 0)
// 1
// 2
// 3
// 4
// 5
// 6
// 7
// 8
// 9

Test3:

async function async1() {
  console.log("A1-start");
  await async2();
  console.log("A1-end");
}
async function async2() {
  console.log("A2");
}
console.log("start");
setTimeout(function () {
  console.log("T1");
}, 0);
async1();
new Promise(function (resolve) {
  console.log("P1");
  resolve();
}).then(function () {
  console.log("P1-then");
});
console.log("end");
// start
// A1-start
// A2
// P1
// end
// A1-end
// P1-then
// T1

);
setTimeout(function () {
console.log(“T1”);
}, 0);
async1();
new Promise(function (resolve) {
console.log(“P1”);
resolve();
}).then(function () {
console.log(“P1-then”);
});
console.log(“end”);
// start
// A1-start
// A2
// P1
// end
// A1-end
// P1-then
// T1


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值