javascript是单线程。单线程就意味着,所有任务需要排队,前一个任务结束,才会执行后一个任务。
所有的任务分为两种,一种是同步任务,一种是异步任务。
同步任务指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务;
异步任务指的是,不进入主线程、而进入"任务队列"(task queue)的任务,只有等主线程任务执行完毕,"任务队列"开始通知主线程,请求执行任务,该任务才会进入主线程执行。
我们可以通过代码来感受一下。
console.log(1);
setTimeout(function() {
console.log(2);
});
console.log(3);
由此我们可以看到,console.log属于同步任务,setTimeout属于异步任务。
javascript执行代码的顺序为从上到下一次执行,如果setTimeout是同步任务就应该是输出123,既然输出的是132也就是说,setTimeout里的函数并没有立即执行,而是延迟了一段时间,满足一定条件后,才去执行的,这类代码,我们叫异步代码。
首先我们要明确一点,宏任务和微任务都在任务队列。
宿主发起的任务为宏观任务,如setTimeout、setInterval。
为了更好地理解,我们可以将其比喻为到银行办理业务的用户,由于业务员一次只能办理一个用户的业务,每一个用户都可以看作是一个宏任务。
微任务仅来自于我们的代码。它们通常是由 promise 创建的,微任务也被用于 await 的“幕后”,因为它是 promise 处理的另一种形式。
对于微任务的理解我们依然可以使用银行办理业务来比喻,对于正在办理业务的人,在当前业务办理完成后,可能还会有其他业务要办,那么这个后来添加的任务就是微任务。
那么下一个宏任务就会往后延迟,在当前宏任务的微任务没有全部完成时是不会执行下一个宏任务的。
也就是说,每个宏任务之后,引擎会立即执行微任务队列中的所有任务,然后再执行其他的宏任务,或渲染,或进行其他任何操作。
微任务会在执行任何其他事件处理,或渲染,或执行任何其他宏任务之前完成。
为什么有了宏任务,还会有微任务存在?因为宏任务太占用性能,当需要一些较早就准备好的方法,排在最后才执行的时候,又不想新增一个宏任务,那么就可以把这些方法,一个一个的放在微任务队列里面,在这个宏任务中的代码执行完后,就会执行微任务队列。
那么,我们也可以利用代码更好地理解宏任务和微任务。
setTimeout(() => console.log(4))
new Promise(resolve => {
resolve()
console.log(1)
}).then(_ => {
console.log(3)
})
console.log(2)
效果如下
我们可以根据输出结果来判断哪些是宏任务,哪些是微任务。
但是根据结果我们可以看出,首先输出的是1,而不是2,这也就说明new Promise不是异步任务,是同步任务,resolve和then才是异步的。
也就是说当前代码中只有then和setTimeout才是异步的,在同步代码执行完成后才回去检查是否有异步任务完成,并执行对应的回调,而微任务又会在下一个宏任务之前执行,因此输出1,2,3,4。
事件循环 是一个在 JavaScript 引擎等待任务,执行任务和进入休眠状态等待更多任务这几个状态之间转换的无限循环。
引擎的一般算法:
当有任务时:
执行任务的顺序