1. JS代码的执行顺序
JS引擎执行代码是是单线程,同一时刻只会有一个进程执行JS代码,多任务需要排队。
JavaScript的单线程,与它的用途有关,作为浏览器脚本语言,JavaScript的主要用途是与用户交互,以及操作DOM。这决定了它只能是单线程,否则会带来很多复杂的同步问题。这种模式可能会阻塞代码,导致代码执行效率低下。
为了规避这些问题,出现了异步任务,用回调函数的方式来实现异步代码的存放于执行。
将所有的任务分为两种:同步任务
和 异步任务
同步任务
:在主线程上排队执行任务,只有前一个任务执行完毕,才能执行下一个任务
异步任务
:不进入主进程,而进入任务队列,在主进程空闲时,事件触发线程会从任务队列取出一个任务(即异步的回调函数)放入主进程中执行。
2. 为什么会有异步
如果代码只能自上而下执行,如果上一行解析时间很长,那么下面的代码就会被阻塞。用户就会想"这么卡,算了不用了",这样就导致了很差的用户体验。而使用异步编程就会将任务添加到任务队列中,优先执行同步代码,将回调函数或者比较难加载的放到队列中,就会节省很多时间。
3. 任务队列的执行顺序
异步函数中还有微任务与宏任务
宏任务
:整体代码script、setTimeOut、setInterval、BOM/DOM交互事件
微任务
:promise的resolve/reject、promise.then、process.nextTick(node)、MutaionObserver
先微任务microtask队列,再宏任务macrotask队列 。
所以:同步任务
=>异步任务
,微任务
=>宏任务
例如:
console.log('event start')
setTimeout(function () {
console.log('setTimeout');
});
new Promise(function(resolve,reject){
console.log('promise start')
resolve()
}).then(function(){
console.log('promise end')
})
console.log('event end')
//执行结果:
event start
promise start
event end
promise end
setTimeout
注意:new Promise是会进入到主线程中立刻执行,而promise.then则属于微任务。
4.简单练习
console.log(1)
setTimeout(function(){
console.log(2)
},0)
console.log(3)
执行结果:1 3 2
//关于异步的:
setTimeout(()=>{
console.log('setTimeout1')
},0)
let p = new Promise((resolve,reject)=>{
console.log('Promise1')
resolve()
console.log('Promise2')
})
p.then(()=>{
console.log('Promise3')
})
执行结果:
Promise1
Promise2
Promise3
setTimeout1
console.log('event 1')
Promise.resolve().then(() => {
setTimeout(() => {
console.log('setTimeout 1')
}, 0)
console.log('Promise 1')
}).then(() => {
console.log('Promise 2')
})
console.log('event 2')
setTimeout(() => {
console.log('setTimeout 2')
}, 0)
执行结果:
event 1
Promise 1
event 2
Promise 2
setTimeout 2
setTimeout 1