2020前端面试(十三)-js执行机制相关

点这里,欢迎关注

一.浏览器多进程与js单线程:

https://segmentfault.com/a/1190000012925872

1.进程与线程:

进程是CPU资源(内存)分配的最小单位。

线程是CPU最小的调度单位。是建立在进程的基础上的一次程序运行单位,一个进程中可以有多个线程。

2.浏览器的多进程:

1.浏览器主进程(Browser进程):(负责协调、主控)

  • 负责浏览器界面显示,与用户交互。如前进,后退等
  • 负责各个页面的管理,创建和销毁其他进程
  • 将渲染进程得到的内存中的Bitmap,绘制到用户界面上
  • 网络资源的管理,下载等

2.浏览器渲染进程(也称Render进程,浏览器内核,比如bink):内部是多线程的;每个Tab页面都有一个渲染进程。

  • 页面渲染
  • js脚本执行
  • 事件处理

3.GPU进程:用于3D绘制等

4.第三方插件进程:每种类型的插件对应一个进程,仅当使用该插件时才创建。

3.浏览器渲染进程中的线程:

牢记:内核即浏览器渲染进程;js引擎即js引擎线程。

(1)GUI渲染线程,也称UI线程

  • 负责渲染浏览器界面,解析HTML,CSS,构建DOM树和RenderObject树,布局和绘制等。
  • 当界面需要重绘(Repaint)或由于某种操作引发回流(reflow)时,该线程就会执行
  • GUI渲染线程与JS引擎线程是互斥的,当JS引擎执行时GUI线程会被挂起。

(2)js引擎线程

  • 浏览器渲染进程中的线程大哥

  • 也称为js引擎,js内核,比如V8引擎

  • js引擎线程负责处理Javascript脚本程序,执行代码。

  • JS引擎一直等待着任务队列​(⭐️)​ 中任务的到来,然后加以处理。

  • 每个tab页面都要一个渲染进程,每个渲染进程只有一个js引擎线程,也就是经常说的js引擎是单线程的。**为什么js引擎线程要设计成单线程呢?**因为js设计的主要目的是与用户进行交互,进行简单的dom操作,如果设计为多线程,则还需要处理同步等问题,就变得复杂了。

  • GUI渲染线程与JS引擎线程是互斥的,所以如果JS执行的时间过长,这样就会造成页面的渲染不连贯,导致页面渲染加载阻塞。

(3)事件触发线程

  • 用于控制事件,事件触发时(click,load)会将事件的处理函数推进事件队列

(4)定时器触发线程

  • 浏览器定时计数器并不是由JavaScript引擎计数的。
  • 浏览器通过单独线程来计时并触发定时,计时完毕后,添加到事件队列中,等待JS引擎空闲后执行。

(5)http异步请求线程

  • 在通过XMLHttpRequest创建连接后,浏览器会新开一个线程来发送http请求。
  • 将检测到状态变更时,如果设置有回调函数,http异步请求线程就会产生状态变更事件,将这个回调放入事件队列中,交由js引擎处理。

由于GUI渲染线程与js线程是互斥的,所以js可能会阻塞页面的加载。

4.WebWorker线程:

webwork是HTML5新增的用于在后台线程运行js脚本的方法。

  • 创建Worker时,JS引擎向浏览器申请在当前渲染进程中开一个子线程(子线程是浏览器开的,完全受主线程控制,而且不能操作DOM)
  • JS引擎线程与worker线程间通过特定的方式通信postMessage API,需要通过序列化对象来与线程交互特定的数据)

因此,耗时的操作可以开一个worker线程,这样就不会影响js线程的执行。

因此,并不能说webwork使得js引擎变成了多线程,js引擎还是单线程,只是现在为它开了一个新的线程来处理Js代码。

5.异步任务的由来:

js是单线程,一次只能完成一件任务,如果有多个任务,就必须排队。如果一个任务耗时很长,会拖延整个程序的执行,影响用户体验。为了解决这个问题,Javascript语言将任务的执行模式分成两种:同步(Synchronous)和异步(Asynchronous)。

6.js执行机制:

https://www.cnblogs.com/wangziye/p/9566454.html

js的执行机制就是 浏览器内核多个线程之间的配合 和 事件循环机制 :

1.同步任务会直接进行主线程的执行栈中,然后js先执行 执行栈中的同步任务

2.在执行的过程中,若遇到异步任务,则提交给对应的异步线程处理

3.在这些异步线程中,若监听到某异步任务已经被触发了,即发送了点击,或者定时器时间已到,则将其放入任务队列(task queue)中

4.执行栈中的同步任务执行完后,主线程会不断的轮询查找任务队列中的任务,并执行任务。

image-20200925075620369

7.从任务列表中取出并执行异步任务的原则:

(1)异步任务的分类:

宏任务(macrotask):

script (整体代码),dom事件,ajax,setTimeout,setInterval,setImmediate,requestAnimationFrame,I/O,UI rendering

注意:setTimeout的优先级比setImmediate高

微任务(microtask):

promise.then,mutation回调,process.nextTick

注意:process.nextTick的优先级比promise.then高

(2)具体原则:

主线程中的执行栈在执行完同步任务之后,主线程会对事件队列(event queque)进行轮询,

会先去执行微任务队列中的所有任务,

执行完毕后再去执行宏任务队列中的一个任务,

每个宏任务执行结束后,在另一个宏任务执行前,需要检查微任务队列是否还存在任务,若存在,则需执行完才能执行下一个宏任务。

8.js执行机制分析题:

(1)第一题:超级大综合

//主线程直接执行
console.log('1');
//丢到宏事件队列中
setTimeout(function() {
    console.log('2');
    process.nextTick(function() {
        console.log('3');
    })
    new Promise(function(resolve) {
        console.log('4');
        resolve();
    }).then(function() {
        console.log('5')
    })
})
//微事件1
process.nextTick(function() {
    console.log('6');
})
//主线程直接执行
new Promise(function(resolve) {
    console.log('7');
    resolve();
}).then(function() {
    //微事件2
    console.log('8')
})
//丢到宏事件队列中
setTimeout(function() {
    console.log('9');
    process.nextTick(function() {
        console.log('10');
    })
    new Promise(function(resolve) {
        console.log('11');
        resolve();
    }).then(function() {
        console.log('12')
    })
})
//输出:1,7,6,8,2,4,3,5,9,11,10,12

(2)第二题

setTimeout(function() {
    console.log(1)
}, 0);
new Promise(function(resolve, reject) {
    console.log(2)
    for (var i = 0; i < 10000; i++) {
        if(i === 10) {console.log(10)}
        i == 9999 && resolve();
    }
    console.log(3)
}).then(function() {
    console.log(4)
})
console.log(5);
//最终执行结果:2 10 3 5 4 1

(3)第三题:考察setImmediate,process.next的优先级

setImmediate(function () {
  console.log(1);
}, 0);
setTimeout(function () {
  console.log(2);
}, 0);
new Promise(function (resolve) {
  console.log(3);
  resolve();
  console.log(4);
}).then(function () {
  console.log(5);
});
console.log(6);
process.nextTick(function () {
  console.log(7);
});
console.log(8);
//输出结果是3 4 6 8 7 5 2 1

(4)第四题:考察process.next的优先级

setTimeout(function () {
  console.log(1);
}, 0);
new Promise(function (resolve, reject) {
  console.log(2);
  resolve();
})
  .then(function () {
    console.log(3);
  })
  .then(function () {
    console.log(4);
  });
process.nextTick(function () {
  console.log(5);
});
console.log(6);
// 输出为 2 6 5 3 4 1

(5)第五题:

//给出以下代码的执行结果,并说明原因
for (var i = 0; i < 5; i++) {
    setTimeout(function () {
        console.log(i);
    }, 1000);
}
console.log(i);
//输出:先输出一个5,然后输出5个5
//原因:setTimeout属于异步任务,主线程中的同步代码执行完毕后才会去执行任务队列中的任务。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值