winter 老师《重学前端》学习笔记
当拿到一段js代码,浏览器或node环境首先要做的就是,传递给js引擎,并且要求它去执行。ES5之后js中引入了promise,这样不需要浏览器的安排,js引擎本身也可以发起任务了。
把宿主发起的任务成为宏观任务,把js引擎发起的任务成为微观任务
宏观和微观任务
在操作系统中,js引擎等待宿主环境分配宏观任务,通常等待的行为都是一个事件循环。
while(true){
r = wait();
executer(r);
}
整个循环要做的事情基本就是反复“等待--执行”。这里每次的执行都是一个宏观任务,宏观任务的队列就相当于事件循环。宏任务中,js的promise还会产生异步代码,js保证这些异步代码在一个宏任务中完成,因此,每个宏观任务中又包含一个微观任务队列
有了宏观任务和微观任务机制,Promise 永远在队列尾部添加微观任务;setTimeout 等宿主 API,则会添加宏观任务。
promise
promise是js语言提供的一种标准化的异步管理方式。总体思想:需要异步操作的函数,不返回真实结果,而返回一个“ 承诺”,等待“承诺”兑现函数就会被调用(promise的then方法的回调)
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"))
}).then(()=> {
console.log("c3")
}).then(()=> {
console.log("c4")
})
var f = new Promise(function (resolve, reject) {
resolve()
});
f.then(() => {
var begin = Date.now();
while (Date.now() - begin < 1000);
console.log("f1");
new Promise(function (resolve, reject) {
resolve()
}).then(() => console.log("f2"))
}).then(() => {
console.log("f3")
}).then(()=> {
console.log("f3")
})
输出结果:c1 f1 c2 c3 f2 f3 c4 f4 d
即使强制1s的执行耗时,c仍然优先于d执行。会把本次宏任务的所有微任务执行完,再执行下一个宏任务。
function sleep(time) {
return new Promise((resolve, reject)=> {
console.log('b');
setTimeout(resolve, time);
})
}
console.log('a')
sleep(5000).then(()=> console.log('c'))
输出结果: a b c
总结异步任务执行的顺序:
- 首先分析有多少个宏任务
- 在每个宏任务中,分析有多少个微任务
- 根据调用次序,确定宏任务中的微任务执行次序
- 根据宏任务的触发规则和调用次序,确定宏任务的执行次序
- 确定整个顺序
新特性:async/await
async函数必定返回promise,把所有返回promise的函数都可以认为是异步函数
function sleep(time){
return new Promise((resolve, reject)=> {
setTimeout(resolve, time);
})
}
async function foo(name){
await sleep(2000);
console.log(name);
}
async function foo2(){
await foo('a');
console.log('c');
await foo('b');
}
foo2();
输出结果: a c b
此外,generator/iterator 也常常被跟异步一起来讲,但是 generator 并非被设计成实现异步,所以有了 async/await 之后,generator/iterator 来模拟异步的方法应该被废弃。
制作红绿灯
现在要实现一个红绿灯,把一个圆形 div 按照绿色 3 秒,黄色 1 秒,红色 2 秒循环改变背景色
<div id="circle" style="width: 100px;height: 100px;border-radius: 100px;background-color: green;"></div>
<script>
document.addEventListener('DOMContentLoaded', function(){
function sleep(time){
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve();
}, time);
})
}
async function changeColor(color, time){
document.getElementById('circle').style.backgroundColor = color;
await sleep(time);
}
async function main(){
while (true) {
await changeColor('green', 3000)
await changeColor('yellow', 1000)
await changeColor('red', 2000)
}
}
main()
})
</script>