nextTick 是 Vue 的一个核心实现,在开发过程中会遇到在声明周期中没有获取到及时更新的值或Dom,我们会使用nextTick,将nextTick(callBack)放到异步任务队列中
在下主线程任务执行完成后再去执行。
主要涉及以下知识点
1. JS 的运行机制。
2. 宏观任务 macro task
3. 微观任务 micro task
一:JS 的运行机制
javaScript是一门单线程语言,所以一切javascript版的”多线程”都是用单线程模拟出来的,一切javascript多线程都是纸老虎!
javaScript 是单线程的, 那么可以预见会有等待加载这种,如果网页初始化数据量很大,执行时间很长,那么对用户体验是十分不友好的,所以为了解决这种问题,出现了同步、异步任务
![](https://i-blog.csdnimg.cn/blog_migrate/fc06f88d3ad8a7355c673718442e868f.png)
1. 同步和异步任务分别进入不同的执行”场所”,同步的进入主线程,异步的进入 Event Table并注册函数直接返回回调或等待完成时返回回调。
2. 当指定的事情完成时,Event Table会将这个函数移入Event Queue(遵循先进执行的原则)。
3. 主线程内的任务执行完毕为空,会去Event Queue读取对应的函数,进入主线程执行。
4. 上述过程会不断重复,也就是常说的Event Loop(事件循环)。
我们不禁要问了,那怎么知道主线程执行栈为空啊?js引擎存在monitoring process进程,会持续不断的检查主线程执行栈是否为空,一旦为空,就会去Event Queue那里检查是否有等待被调用的函数。
那么接下来看几行代码
setTimeout (function () {
console.log(‘定时器开始啦’)
});
new Promise(function (resolve) {
console.log(‘马上执行for循环啦’);
for (var i = 0; i < 10000; i++) {
i == 99 && resolve();
} }).then(function () {
console.log(‘执行then函数啦’)
});
console.log(‘代码执行结束’);
执行结果
1. 马上执行for循环啦
2. 代码执行结束
3. 执行then函数啦
4. 定时器开始啦
二:JS 循环执行机制
大家不知道有没有疑问 1. 马上执行for循环啦 2. 代码执行结束 大家肯定不会有疑问
因为单线程执行,重上往下。那么对于为什么 promise 在执行 setTimeout, 不是应该setTimeout 先进入Event Queue中的么? 这里就涉及js执行顺序、宏观、微观
js的循环顺序、先执行宏观(包含主线程)执行完毕后、在执行微观任务、然后再次执行宏观,找到其中一个任务队列执行完毕,再执行所有的微任务
![](https://i-blog.csdnimg.cn/blog_migrate/5b418c1a7088f84fe3a3703b9e3339c5.png)
1. 宏观 script,setTimeout,setInterval,setImmediate, MessageChannel,postMessage
setImmediate
该方法用来把一些需要长时间运行的操作放在一个回调函数里,在浏览器完成后面的其他语句后,就立刻执行这个回调函数
var immediateID = setImmediate(func, [param1, param2, …]);
immediateID 是这次setImmediate方法设置的唯一ID,可以作 为 window.clearImmediate 的参数(取消执行).
func 是将要执行的回调函数
参数param1 param2 ..都会直接传给函数func
MessageChannel
是一个实例化构造函数接口允许我们创建一个新的消息通道,并通过它的两个属 性发送数据
const channel = new MessageChannel();
channel 有两个方法
channel.port2 channel.port2.postMessage(1)给 port1发送消息
channel.port1 channel.port1.onmessage 接收消息执行回调
2. 微观 Promise,process.nextTick,MutationObsever
我们再来看一段复杂的代码
主线程
console.log(’99’);
异步 宏观
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(’77’);
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’)
})
})
执行结果
第一轮事件循环
先走 主线程宏观 打印 99、 77
执行微观任务 6、8
第二轮事件循环
先走该任务的异步宏观 2、4
在执行该任务的微观任务 3 .5
第三轮事件循环
先走该任务的异步宏观 9、11
在执行该任务的微观任务10、12