javascript是一门单线程语言,也就是说代码只能一个接一个地被顺序处理,同一个时间只能做一件事。如果做某一件事时间太长,后面的执行就需要等待,需要等前面的事件执行完成,才可以往后执行。
所以为了解决这个问题,js就委托宿主浏览器去帮忙执行耗时的任务,执行完成后,再通知js去执行回调函数,而宿主环境帮我们去执行的这些耗时任务就是异步任务。 js 本身是无法发起异步的,但是 es5 之后提出了 Promise 可以进行异步操作
js执行的流程
-
主线程先判断任务类型
- 如果是同步任务,主线程自己执行
- 如果是异步任务,交给宿主环境(浏览器)执行
-
浏览器进行异步任务的执行,每个异步执行完后,会将回调放进任务队列,先执行完成的先放进任务队列,依次放入。
-
等主线程任务全部执行完后,发现主线程没有任务可执行了,会取任务队列中的任务,由于任务队列里是依次放入进来的,所以取得时候也会先取先进来的,也就是先进先出原则 -
在任务队列中取出来的任务执行完后,在取下一个,依次重复,这个过程也称为 eventLoop 事件循环
简单了解一下异步任务
异步任务又分为宏任务和微任务
宏任务一般是:包括整体代码script,setTimeout,setInterval、setImmediate。你会发现所有宏任务都属于Web API接口下的,都是浏览器提供,有宿主发起的一个异步任务,这不是js提供的
微任务:原生Promise(Promise.then里面的回调才是一个微任务、process.nextTick、 MutationObserver 。这是JAvaScript标准的内置对象,由js自身发起的异步。
异步任务的执行顺序
- 先执行宏任务
- 宏任务执行完后看微任务队列是否有微任务
- 没有微任务执行下一个宏任务
- 有微任务将所有微任务执行
- 执行完微任务,执行下一个宏任务
看一个简单的练习
setTimeout(() => {
console.log(2);
new Promise((resolve) => {
console.log(3);
resolve()
}).then(() => {
console.log(4)
})
})
new Promise((resolve) => {
console.log(5);
resolve()
}).then(() => {
console.log(6)
})
setTimeout(() => {
console.log(7)
})
结果为5、6、2、3、4、7,
遇到宏任务中有微任务的话,先把这个宏任务中的微任务执行完,也就是要把微任务清空,才会去执行下一个微任务