JavaScript中的异步和任务轮询
众所周知,我们JavaScript是一门单线程的语言,虽然借js是单线程的。但是我们的执行环境,也就是浏览器。它是多线程的。总得来说,浏览器分为以下几个线程。第一个就是我们的js线程,这个负责的是解释和执行我们的js代码
第二个是Gui,也就是负责绘制页面的。这个和Js线程是互斥的。也就是gs县城和gy县城不能同时执行。
第三个是处理网络请求的线程。
第四个是处理浏览器事件的线程。
这里面最重要的就是js线程。
然后gs是一门单线程的语言。为了实现异步,浏览器采用了一种叫做任务轮询的机制。那么gs是如何决定不同操作的执行顺序呢?
第一个是同步和异步。
同步代码永远比异步代码先执行。既然是引擎遇到同步操作时将同步操作推到一个调用栈里面。而遇到一波操作时江他们推到一个任务队列里面。当调用栈执行结束后就开始执行任务队列里面的代码。
第二个是异步的任务队列里面也分为两类
以nodejs执行环境为例。process.nexttick和promise属于microTask,setInterval和setTimeout属于macroTask。microTask队列执行完成后才会去执行macroTask队列。
setTimeout1 = setTimeout(function() {
console.log('---1---')
}, 0)
setTimeout2 = setTimeout(function() {
Promise.resolve()
.then(() => {
console.log('---2---')
})
console.log('---3---')
}, 0)
new Promise(function(resolve) {
console.time("Promise")
for (var i = 0; i < 1000000; i++) {
i === (1000000 - 1) && resolve()
}
console.timeEnd("Promise")
}).then(function() {
console.log('---4---')
});
console.log('---5---')
js引擎从上到下解析代码,遇到setTimeout1
和setTimeout2
,推入macroTask队列,继续执行.这里new Promise
是一个同步操作,所以到打印出1自增到1000000的执行时间,然后将then回调推入microTask队列.然后是同步代码打印---5---
.至此,同步代码已经执行完成.开始执行microTask队列中的任务,也就是console.log('---4---')
,然后执行macroTask队列中的代码,首先是console.log('---1---')
,然后setTimeout2
中遇到Promise.then()
,将其推入microTask队列中,继续执行console.log('---3---')
,最后执行的是console.log('---2---')