JS为一门单线程语言;JS的执行机制是Event Loop事件循环
JS单线程,就是按语句出现顺序执行--等待前一个任务的结束,再去执行下一个任务,称为JS执行的主线程。
普通的JS任务按语句的出现顺序,在主线程上执行,这类任务称为同步任务;但是对于执行时间很长的任务(类似于Ajax请求),就会阻塞代码的执行,为避免此情况的产生,可以先将该类任务挂起,这类任务称为异步任务。
首先放个初级代码
// code1
console.log('1')
setTimeout(function() {
console.log('2')
}, 0)
console.log('3')
从理论上总结JS的执行机制:
(1)同步和异步任务进入不同的执行线,同步任务直接按顺序进入主线程,异步任务进入到Event Table中并注册对应的回调函数
(2)指定的事情完成时,Event Table会将函数移入事件队列(Event Queue)中
(3)主线程任务执行,执行完毕后,读取事件队列函数到主线程中并执行
(4)JS事件循环,不断执行上述操作
上面code1的输出结果为:1,3,2。注意code1中setTimeout的延迟为0毫秒,但是并没有立即执行,仍然在最后输出,即为异步任务。
更新代码段
// code2
setTimeout(function() {
console.log('2')
}, 2000)
sleep(5000)
// 5秒后输出‘2’
// 尽管延迟了3秒,但是主线程的执行花了5秒钟
// 开始时console被注册到Event Table,开始计时;3秒的时候console进入到事件队列;5秒的时候console进入到主线程
插入总结一下JS中的同步任务和异步任务有哪些
异步任务:ajax请求、事件绑定、定时器、new Promise的回调(then、catch)以及其他一些回调函数
同步任务:new Promise构造函数、其它script 语句
对任务进行更细致的划分,分为宏任务和微任务,其中
宏任务:包括整体代码script,setTimeout,setInterval
微任务:Promise,Node.js的process.nextTick
重新描述JS的执行过程:
整体代码为宏任务,开始第一次事件循环,执行完宏任务后执行微任务,结束第一次事件循环;开始第二次循环,看执行宏任务,再执行微任务,结束第二次循环。不断重复循环上述执行。
接下来以promise为例,更新代码
// code3
setTimeout(function() {
console.log('1');
}, 0)
new Promise(function(resolve) {
console.log('2');
}).then(function() {
console.log('3');
})
console.log('4');
执行过程:
- 整段代码进入到主线程
- setTimeout 回调被注册进入Event Table,而后进入Event Queue
- Promise构造函数立即执行,console语句输出2,then回调进入到微任务的Event Queue中
- console语句立即执行,输出4
- 此时第一次循环的宏任务执行完毕,开始执行第一次循环里面的微任务,输出promise的then回调里面的console,输出3
- 结束第一次循环,开始第二次循环,执行宏任务setTimeout,输出1
附上找来的一个总结性例子
// process.nextTick方法可以在当前"执行栈"的尾部----
// 下一次Event Loop(主线程读取"任务队列")之前----触发回调函数。
// 也就是说,它指定的任务总是发生在所有异步任务之前
// code4, 输出结果再文末
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')
})
})
最后,附上爬这篇总结的导火代码:
testFunction() {
// ...
this.intershipList[index].logDetail = this.getgetLogDetail(index, id)
this.intershipList.splice(this.intershipList, 0)
/* this.getLogDetail(index, id) */
// ...
},
getLogDetail(index, id) {
// ...
this.$axios
.post('***', postData)
.then(response => {
if (response.success) {
return response.data;
} else {
return []
}
/* if (response.success) {
this.intershipList[index].logDetail = response.data
this.intershipList.splice(this.intershipList, 0)
} */
})
.catch(err => {
console.log(err)
})
}
现在再来看,就很清楚的明白为什么intershipList的数据没能更新啦。另外,上述代码中使用数组的splice操作方法,更新视图,参考vue数据更新,视图无法更新问题 。
// code4输出结果
// 1 7 6 8 2 4 3 5 9 11 10 12
网友评论