一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第3天,点击查看活动详情。
单线程
JavaScript是一门单线程语言,即同一时间段只能执行一件事,单线程意味着如果同个时间有多个任务的话,这些任务就需要排队等待,上一个任务执行完才会执行下一个任务。
同步任务跟异步任务
为什么要分同步与异步
由于js同一时间只能执行一个任务,多个任务需要进行排队。假如当前的任务执行时间较长,比如ajax获取数据,用户就需要等待数据回来才能进行下一步,这个时间段用户不能进行任何操作,严重影响用户体验。
js是单线程的,但又可同时进行异步操作,这两者不是完全相反的吗?js是单线程模式,但是js的宿主浏览器不是单线程。
同步
同步任务就是指主线程上排队的任务,当一个任务执行完成才会继续执行下一个任务。
异步
异步任务就是指不进入主线程,而进入任务队列的任务。这个队列的所有任务进入主线程执行,而是进入浏览器提供的线程执行,执行完成之后会产生一个回调函数,并通知主线程。主线程执行完当前任务就会调取最早通知的主线程的回调函数,使其进入主线程中执行。
宏微任务
宏任务
参与了事件循环的任务。 回到 Chromium 中,需要处理的消息主要分成了三类:
- Chromium 自定义消息
- Socket 或者文件等 IO 消息
- UI 相关的消息
- 与平台无关的消息,例如 setTimeout 的定时器就是属于这个
- Chromium 的 IO 操作是基于 libevent 实现,它本身也是一个事件驱动的库
- UI 相关的其实属于 blink 渲染引擎过来的消息,例如各种 DOM 的事件
其实与 JavaScript 的引擎无关,都是在 Chromium 实现的。
微任务
直接在 Javascript 引擎中的执行的,没有参与事件循环的任务。
- new Promise().then 回调
- MutationObserver,监控dom节点变化;MutationObserver使用“异步”+“微任务”的方式,替代旧版mutation event这个同步事件,异步解决同步操作的性能问题,微任务解决了实时性的问题;
- Object.observe,已经废弃了,用Proxy对象替代;
event loop 事件循环
- 浏览器的事件循环,是在渲染进程中的。
- 执行一个宏任务,栈中没有就从事件队列中获取。
- 执行过程中如果遇到微任务,就添加到微任务的队列中。
- 当前这个宏任务执行完毕后,立即执行当前微任务队列的所有微任务。
- 当前宏任务执行完毕,GUI线程接管渲染。
- 渲染完毕后,JS线程继续接管,开始下一个宏任务。
简化就两步:
执行一个宏任务,执行完它对应的所有微任务;
小试牛刀
使用同步异步、宏微任务以及事件循环,判断以下函数的执行顺序
async function async1() {
console.log("async1 start");
await async2();
console.log("async1 end");
}
async function async2() {
console.log("async2");
}
async1();
setTimeout(() => {
console.log("timeout");
}, 0);
new Promise(function (resolve) {
console.log("promise1");
resolve();
}).then(function () {
console.log("promise2");
});
console.log("script end");
//正确答案是
console.log("async1 start");
console.log("async2");
console.log("promise1");
console.log("script end");
console.log("async1 end");
console.log("promise2");
console.log("timeout");
嘿嘿上面的搞明白了,现在看下这个升级版的
console.log('global')
for (var i = 1;i <= 5;i ++) {
setTimeout(function() {
console.log('set:',i)
},i*1000)
console.log('i:',i)
}
new Promise(function (resolve) {
console.log('promise1')
resolve()
}).then(function () {
console.log('then1')
})
setTimeout(function () {
console.log('timeout2')
new Promise(function (resolve) {
console.log('timeout2_promise')
resolve()
}).then(function () {
console.log('timeout2_then')
})
}, 1000)
正确答案是:
i: 1
VM12611:5 i: 2
VM12611:5 i: 3
VM12611:5 i: 4
VM12611:5 i: 5
VM12611:9 promise1
VM12611:12 then1
597
VM12611:3 set: 6
VM12611:16 timeout2
VM12611:18 timeout2_promise
VM12611:21 timeout2_then
4VM12611:3 set: 6