JavaScript执行机制学习总结

执行机制相关知识点

1、JavaScript是一门什么语言

        JavaScript是一门单线程语言,比如说页面上有一个DOM,一个线程删除此DOM节点,另一个线程给节点添加样式。

2、同步和异步

        如果JS中不存在异步,只能自上而下执行,如果上一行解析时间很长,那么下面的代码就会被阻塞。 对于用户而言,阻塞就意味着"卡死",这样就导致了很差的用户体验。

同步:比如说在一个函数返回的时候,就能够得到预期结果: console.log()。

异步:在函数返回的时候,调用者还得不到预期结果,而是通过一定手段得到:setTimeout

1、同步和异步任务分别进入不同的执行"场所",同步的进入主线程,异步的进入Event Table并注册函数。
2、当Event Table中指定的事情完成时,会将这个函数移入Event Queue。
3、主线程内的任务执行完毕为空,会去Event Queue读取对应的函数,进入主线程执行。
4、上述过程会不断重复,也就是常说的Event Loop(事件循环)。
5、我们不禁要问了,那怎么知道主线程执行栈为空啊?js引擎存在monitoring process进程,会持续不断的检查主线程执行栈是否为空,一旦为空,就会去Event Queue那里检查是否有等待被调用的函数。

3、任务队列

        同步任务:在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行最后一个任务

        异步任务:不进入主线程,而是进入Event Table并注册函数

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

 4、JavaScript的宏任务与微任务

        macro-task(宏任务):包括整体代码script、setTimeout、setInterval、setImmediate、I/O、UI rendering
        micro-task(微任务):Promise.then、process.nextTick、Object.observe、MutationObserver

        Promise中的async,在标有async的函数会立即执行,所以说promise中的代码会立即执行

        不同类型的任务会进入对应的Event Queue。
  事件循环的顺序,决定js代码的执行顺序。进入整体代码(宏任务)后,开始第一次循环。接着执行所有的微任务。然后再次从宏任务开始,找到其中一个任务队列执行完毕,再执行所有的微任务。

5、以实例来说明JavaScript的执行机制

        5.1 同步

console.log(1);
console.log(2);
console.log(3);
/*
    执行结果:1、2、3
    同步任务,按照顺序一步一步执行
*/

        5.2 同步和异步

console.log(1);
setTimeout(function() {
    console.log(2);
},1000)
console.log(3);
/*
    执行结果:1、3、2
    同步任务,按照顺序一步一步执行
    异步任务,放入消息队列中,等待同步任务执行结束,读取消息队列执行
*/

        5.3 异步任务进一步分析

console.log(1);
setTimeout(function() {
    console.log(2);
},1000)
setTimeout(function() {
    console.log(3);
},0)
console.log(4);
/*
    猜测是:1、4、2、3   但实际上是:1、4、3、2
    分析:
        同步任务,按照顺序一步一步执行
        异步任务,当读取到异步任务的时候,将异步任务放置到Event table(事件表格)
中,当满足某种条件或者说指定事情完成了(这里的是时间分别是达到了0ms和1000ms)当指定
事件完成了才从Event table中注册到Event Queue(事件队列),当同步事件完成了,便从
Event Queue中读取事件执行。(因为3的事情先完成了,所以先从Event table中注册到
Event Queue中,所以先执行的是3而不是在前面的2)
*/

        5.4 宏任务和微任务

console.log(1);
setTimeout(function() {
    console.log(2)
},1000);
 
new Promise(function(resolve) {
    console.log(3);
    resolve();
}
).then(function() {
    console.log(4)
});
console.log(5);
/*
    以同步异步的方式来判断的结果应该是:1、3、5、2、4
    但是事实上结果是:1、3、5、4、2
    为什么是这样呢?因为以同步异步的方式来解释执行机制是不准确的,更加准确的方式是宏任务和微任务:
    因此执行机制便为:执行宏任务 ===> 执行微任务 ===> 执行另一个宏任务 ===> 不断循环
        即:在一个事件循环中,执行第一个宏任务,宏任务执行结束,执行当前事件循环中的微任务,
执行完毕之后进入下一个事件循环中,或者说执行下一个宏任务
*/

        5.5 是否彻底理解JavaScript执行机制实例

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')
    })
})
process.nextTick(function() {
    console.log('6');
})
new Promise(function(resolve) {
    console.log('7');
    resolve();
}).then(function() {
    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、 第一轮事件循环流程分析如下:
    整体script作为第一个宏任务进入主线程,遇到console.log,输出1。
    遇到setTimeout,其回调函数被分发到宏任务Event Queue中。我们暂且记为setTimeout1。
    遇到process.nextTick(),其回调函数被分发到微任务Event Queue中。我们记为process1。
    遇到Promise,new Promise直接执行,输出7。then被分发到微任务Event Queue中。我们记为then1。
    又遇到了setTimeout,其回调函数被分发到宏任务Event Queue中,我们记为setTimeout2。
         
    宏任务Event Queue   微任务Event Queue
    setTimeout1         process1
    setTimeout2         then1
     
    上表是第一轮事件循环宏任务结束时各Event Queue的情况,此时已经输出了1和7。
    我们发现了process1和then1两个微任务。
    执行process1,输出6。
    执行then1,输出8。
     
    好了,第一轮事件循环正式结束,这一轮的结果是输出1,7,6,8。
     
2、 那么第二轮时间循环从setTimeout1宏任务开始:
     
    首先输出2。接下来遇到了process.nextTick(),同样将其分发到微任务Event Queue中,
记为process2。new Promise立即执行输出4,then也分发到微任务Event Queue中,记为then2。
     
    宏任务Event Queue     微任务Event Queue
    setTimeout2           process2
                          then2
                           
    第二轮事件循环宏任务结束,我们发现有process2和then2两个微任务可以执行。
        输出3。
        输出5。
        第二轮事件循环结束,第二轮输出2,4,3,5。
 
3、 第三轮事件循环开始,此时只剩setTimeout2了,执行。
        直接输出9。
        将process.nextTick()分发到微任务Event Queue中。记为process3。
        直接执行new Promise,输出11。
        将then分发到微任务Event Queue中,记为then3。
         
    宏任务Event Queue     微任务Event Queue
                            process3
                            then3     
    第三轮事件循环宏任务执行结束,执行两个微任务process3和then3。
        输出10。
        输出12。
        第三轮事件循环结束,第三轮输出9,11,10,12。
 
    整段代码,共进行了三次事件循环,完整的输出为1,7,6,8,2,4,3,5,9,11,10,12。
*/

总结:

执行机制便为:执行宏任务 ===> 执行微任务 ===> 执行另一个宏任务 ===> 不断循环

即:在一个事件循环中,执行第一个宏任务,宏任务执行结束,执行当前事件循环中的微任务,

执行完毕之后进入下一个事件循环中,或者说执行下一个宏任务

参考原文:

https://www.cnblogs.com/shcrk/p/9325779.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值