JavaScript 执行机制

JavaScript 执行机制

javascript是单线程的,javascript是单线程这一核心不会改变。一切javascript版的"多线程"都是基于单线程模拟出来的;

由于单线程,所以javascript任务得一个一个执行(执行完一个然后去执行下一个),那么问题来了,如果一个任务执行需要很长很长的时间,那么下一个任务便会无休止的等待下去(页面卡死);这样是不切合实际的;为了解决这一问题, 同步任务&异步任务 出现了;

一、同步任务

后一个任务等待前一个任务结束,然后再执行,程序的执行顺序与任务的排列顺序是一致的、同步的;

二、异步任务

每一个任务有一个或多个回调函数(callback),前一个任务结束后,不是执行后一个任务,而是执行回调函数,后一个任务则是不等前一个任务结束就执行,所以程序的执行顺序与任务的排列顺序是不一致的、异步的。
例如:AJax请求、定时器、事件、回调函数

三、任务执行过程

任务开始时,会先判断是同步任务还是异步任务,同步任务会进入任务主线程开始执行;异步任务会进入Event Table并注册回调函数(callback)。当异步任务完成,Event Table会把对应的回调函数放入Event Queue;当主线程的任务全部执行完毕后(js引擎存在monitoring process进程,会持续不断的检查主线程执行栈是否为空,一旦为空,就会去Event Queue那里检查是否有等待被调用的函数。),会去Event Queue中读取相应的回调函数来执行;
在这里插入图片描述
图片取自:https://juejin.im/post/59e85eebf265da430d571f89#heading-4

上述过程会不断重复,也就是常说的Event Loop(事件循环)。

例如:

let data = [];
$.ajax({
    url:www.javascript.com,
    data:data,
    success:(res) => {
        console.log('我是ajax异步任务');
    }
})
console.log('我是同步任务');

//我是同步任务
//我是ajax异步任务

ajax为异步任务,进入Event Table中,并注册了success回调函数;ajax执行完成了,该success回调函数被放入 Event Queue 中,等待主线程临幸!
当主线程的任务(console.log(‘我是同步任务’))执行成功了,再去Event Queue中读取success回调函数;
所以先打印 “我是同步任务” 在打印 “我是ajax异步任务”

四、setTimeout

setTimeout也是异步任务

setTimeout(() => {
    console.log('我是setTimeout异步任务');
},3000)
console.log("我是同步任务")
//我是同步任务
...3秒后...
//我是异步任务

setTimeout为异步任务,进入Event Table中,并注册了匿名回调函数;当等待3秒后执行完成了,该回调函数被放入 Event Queue 中,等待主线程临幸!
当主线程的任务(console.log(‘我是同步任务’))执行成功了,再去Event Queue中读取回调函数执行;
所以先打印 “我是同步任务” 在打印 “我是setTimeout异步任务”
注意:setTimeout( fn , 0 ),就算定时为0,其也不是立即执行的,根据HTML的标准,最低是4毫秒。

五、setInterval

setInterval和setTimeout是一样的。只不过setInterval是循环的执行。对于执行顺序来说,setInterval会每隔指定的时间将注册的函数置入Event Queue,如果前面的任务耗时太久,那么同样需要等待。
注意:对于setInterval(fn,ms)来说,,每过ms秒,会有fn进入Event Queue。一旦setInterval的回调函数fn执行时间超过了延迟时间ms,那么就完全看不出来有时间间隔了。


广义划分:同步任务和异步任务
更精细的划分:宏任务和微任务
六、宏任务(macro-task)和 微任务(micro-task)

宏任务包括:整体代码script,setTimeout,setInterval
微任务包括:Promiseprocess.nextTick()

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

new Promise(function(resolve) {
    console.log('promise');
}).then(function() {
    console.log('then');
})

console.log('console');

进入主线程:
setTimeout的回调函数被分发到宏任务Event Queue中
new Promise 立即执行 打印 promise;then()函数进入微任务的Event Queue;
console.log(‘console’);立即执行 打印 console;
这个时候会去判断是否有微任务,如果有执行,如果没有 开始下一循环,此时存在 then()微任务,执行 打印:then;
第一轮事件循环结束了,我们开始第二轮循环,当然要从宏任务Event Queue开始。我们发现了宏任务Event Queue中setTimeout对应的回调函数,立即执行。打印setTimeout
所以 依次是:promise console then setTimeout
在这里插入图片描述
图片取自:https://juejin.im/post/59e85eebf265da430d571f89#heading-4

接下来分析一段复杂的代码

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')
    })
})

进入主线程:

console.log(‘1’); 立即执行 打印 1

setTimeout回调函数被分发到宏任务Event Queue中,我们暂时记录为setTimeout_1

process.nextTick回调函数被分发到微任务Event Queue中,我们暂时记录为process.nextTick_1

new Promise立即执行,打印7,then()函数被分发到微任务Event Queue中,我们暂时记录为then_1

setTimeout回调函数被分发到宏任务Event Queue中,我们暂时记录为setTimeout_2

此时会去判断是否有微任务,如果有执行,如果没有 开始下一循环,此时存在微任务process.nextTick_1和then_1,执行 打印:6 8;
第一轮循环结束了, 目前打印的是 1 7 6 8;

从宏任务Event Queue开始第二轮循环:

console.log(‘2’);立即执行 打印 2;

process.nextTick回调函数被分发到微任务Event Queue中,我们暂时记录为process.nextTick_2

new Promise立即执行 打印 4,then()函数被分发到微任务Event Queue中,我们暂时记录为then_2

此时会去判断是否有微任务,如果有执行,如果没有 开始下一循环,此时存在微任务process.nextTick_2和then_2,执行 打印:3 5;
第二轮循环结束了, 目前打印的是 1 7 6 8 2 4 3 5 ;

从宏任务Event Queue开始第三轮循环:

console.log(‘9’);立即执行 打印 9;

process.nextTick回调函数被分发到微任务Event Queue中,我们暂时记录为process.nextTick_3

new Promise立即执行 打印 11,then()函数被分发到微任务Event Queue中,我们暂时记录为then_3

此时会去判断是否有微任务,如果有执行,如果没有 开始下一循环,此时存在微任务process.nextTick_3和then_3,执行 打印:10 12;

第三轮循环结束了, 目前打印的是 1 7 6 8 2 4 3 5 9 11 10 12;

最后:
javascript是一门单线程语言
Event Loop(事件循环)是javascript的执行机制

完!
本文参考自:
https://juejin.im/post/59e85eebf265da430d571f89#heading-4
https://www.cnblogs.com/mengxiangji/p/10913966.html
https://www.oschina.net/translate/understanding-process-next-tick?print
https://es6.ruanyifeng.com/#docs/promise

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值