简单理解浏览器端的js执行机制Event-Loop

先观为敬

//执行以下JavaScript代码,分析代码执行顺序
console.log('javascript1')

setTimeout(() => {
    console.log('setTimeout1');
    Promise.resolve().then(() => {
        console.log('promise1');
    })
}, 0);

setTimeout(() => {
    console.log('setTimeout2');
    Promise.resolve().then(() => {
        console.log('promise3');
    })

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

Promise.resolve()
    .then(() => {
        console.log('promise4');
    }).then(() => {
        console.log('promise2');
    })
console.log('javascript2');

讲真的,一开始我是懵逼的,反正正确的打印顺序肯定不是从上到下执行的。

js浏览器的执行机制——Event-Loop

这里为什么会强调说是浏览器,我们都知道,在node平台的JavaScript执行机制和浏览器端的执行是有区别的,至于何种区别,不在本文的讨论之中

我们知道js语言是单线程的,这是js语言设计的初衷。起初,作为一个为web开发的语言,如果设计为多线程的,那么就会存在一个矛盾。比如:线程A对一个DOM结构删除了,线程B正在对这个DOM修改,那么浏览器是不是就很蛋疼了。但是在浏览器执行时,又不能按照顺序执行,如果一个任务耗时过长,那么后一个任务也必须等着。那么问题来了,假如我们想打开一个网页,但是该网页中包含的大量图片而且加载很慢,难道我们的网页要一直卡着直到图片完全显示出来?可是问题总归是要解决的,于是就诞生了:

  • 同步执行
  • 异步执行

下面介绍两个例子:

//同步执行
console.log('step1')
console.log('step2')
console.log('step3')
/*
*打印顺序为
*  step1
*  step2
*  step3
*/
//异步执行
console.log('step1')
setTimeout(function(){
   console.log('step2')
},0)
console.log('step3')
/*
*打印顺序为
*  step1
*  step3
*  step2
*/

JavaScript执行机制Event-Loop如下图所示

简单理解浏览器端的js执行机制Event-Loop_第1张图片
image.png

我们尝试通过JavaScript执行机制去分析代码执行顺序。首先先介绍两个概念

  • 宏任务:包括整体代码script,setTimeout,setInterval,setImmediate
  • 微任务:Promise,process.nextTick

分析上面的异步例子
console.log('step1')作为第一级宏任务,需要立即执行
setTimeout(function(){ console.log('step2') },0)作为第二级宏任务,需要等到第一级宏任务执行完成后,再执行
console.log('step3')作为第一级宏任务,需要立即执行

再尝试分析一串简单的代码

setTimeout(function(){
     console.log('step1')
 });
 
 new Promise(function(resolve){
     console.log('step2');
     for(var i = 0; i < 10000; i++){
         i == 99 && resolve();
     }
 }).then(function(){
     console.log('step3')
 });
 
 console.log('step4');

1.setTimeout(function(){ console.log('step1') });作为异步任务放在宏任务队列中,等待执行
2.new Promise立即执行,打印step2,then链是微任务放入微任务队列中等待本次宏任务执行完成后执行
3.console.log('step4')立即执行,打印step4
4.本次宏任务执行完成,查看微任务队列中发现还有promise的then链没有执行,立即执行then链中的console.log('step3')
5.本轮任务完成后,查看宏任务的队列里还有一个定时器,执行定时器的console.log('step1')
所以打印结果为step2-step4-step3-step1

当理解了js浏览器的执行机制后,再来看文章开始的例子就可以很清晰的得出代码打印的结果

javascript1
javascript2
promise4
promise2
setTimeout1
promise1
setTimeout2
promise3
setTimeout3

setTimeout的执行

setTimeout(function(){
     console.log('setTimeout')
 },1000);

通常setTimeout定时器是指在xx秒后执行,其实在js的运行机制里,是在xx秒后将setTimeout里的回调函数推入到event queue队列中,但是并没有立即执行,而是等到js主线程空闲之后再执行,比如上面的代码中,一秒钟后执行console.log('setTimeout'),如果主线程的任务在1秒钟内没有执行完成,那么console.log('setTimeout')也不会在一秒后执行。所以说setTimeout在一秒钟后并且主线程空闲两个条件同时满足才会执行。

你可能感兴趣的:(简单理解浏览器端的js执行机制Event-Loop)