视图
介绍
这是我参与更文挑战的第1
天,活动详情查看:更文挑战
js
中,有两类任务队列:宏任务队列(macro tasks)和微任务队列(micro tasks)。宏任务队列可以有多个,微任务队列只有一个。那么什么任务,会分到哪个队列呢?
- 宏任务:script(全局任务), setTimeout, setInterval, setImmediate, I/O, UI rendering.
- 微任务:process.nextTick, Promise, Object.observer, MutationObserver.
- 微任务始终先于宏任务执行。
setTimeout(()=>console.log("d"), 0)
var r = new Promise(function(resolve, reject){
resolve()
});
r.then(() => {
var begin = Date.now();
while(Date.now() - begin < 1000);
console.log("c1")
new Promise(function(resolve, reject){
resolve()
}).then(() => console.log("c2"))
});
// output: c1
// output: c2
// output: d
这里我们强制了1
秒的执行耗时,这样,我们可以确保任务c2
是在d
之后添加到任务队列。但还是c2
先于d
输出了。
var r = new Promise(function(resolve, reject){
console.log("a");
resolve()
});
r.then(() => console.log("c"));
console.log("b")
// output: a
// output: b
// output: c
分析异步执行的顺序
- 首先分析有多少个宏任务
- 在每个宏任务中,分析有多少个微任务
- 根据调用次序,确定宏任务中的微任务和执行次序
- 根据宏任务的触发规则和调用次序,确定宏任务的执行次序
- 确定整个顺序
console.log('script start');
// 微任务
Promise.resolve().then(() => {
console.log('p1');
});
// 宏任务
setTimeout(() => {
console.log('setTimeout');
}, 0);
var s = new Date();
while(new Date() - s < 50); // 阻塞50ms
// 微任务
Promise.resolve().then(() => {
console.log('p2');
});
console.log('script ent');
/*** output ***/
// one macro task
script start
script ent
// all micro tasks
p1
p2
// one macro task again
setTimeout
上面之所以加50ms
的阻塞,是因为 setTimeout
的 delayTime
最少是 4ms. 为了避免认为 setTimeout
是因为4ms
的延迟而后面才被执行的,我们加了50ms
阻塞。
小思考
例题:(来自winter的重学前端) - 我们现在要实现一个红绿灯,把一个圆形 div 按照绿色 3 秒,黄色 1 秒,红色 2 秒循环改变背景色,你会怎样编写这个代码呢?
思路: - 用promise把setTimeout函数封装成为可用于异步的函数
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
.trafic-light {
height: 100px;
width: 100px;
border-radius: 50%;
margin: 200px auto 0;
border: 1px solid #ececec;
}
</style>
</head>
<body>
<div id="trafic-light" class="trafic-light"></div>
</body>
<script>
let traficEle = document.getElementById('trafic-light');
function changeTraficLight(color, duration) {
return new Promise(function (resolve, reject){
traficEle.style.background = color;
setTimeout(resolve, duration);
})
}
async function traficScheduler() {
await changeTraficLight('green', 3000)
await changeTraficLight('yellow', 1000)
await changeTraficLight('red', 2000)
traficScheduler();
}
traficScheduler();
</script>
</html>