面试题
记得有看过一道有关输出的面试题:
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"))
});
如果有一定js基础可以很轻松的给出 "c1", "c2", "d" 的答案顺序。因为setTimeout是宏任务,而promise是微任务,遇到promise的延迟会放入微任务中,微任务执行完执行宏任务。那么什么是宏任务,什么是微任务呢?
宏任务和微任务
上小学五年级时老师告诉我,JS是一种解释型语言,你写的每一行代码都会放入到JS引擎中执行。那么JS引擎通常在哪里呢?最常见的有浏览器,或者Node环境。而这个所处的环境就是宏任务发起的地方,setTimeout通常是宿主环境调用的JS引擎的一个Api(node环境中是timer模块)。
而promise作为一个内置对象,调用promise时是通过 new promise实例的方法使用,这种在js引擎中调用的过程叫做微任务。
为避免出现死锁的形式,js被设计为一个单线程语言。因此在js线程中,宏任务的调用会放到已有任务队列的后面,按照宏任务队列依次执行。js中宏任务和微任务的执行逻辑如下:
await函数
在ES8的版本新增了两个关键字 await async,依靠这两个关键字可以做到实现异步函数的功能。但底层原理依然是promise。
在promise中 promise内部的函数是同步的,异步只发生在 then的内容中。await/async一样,在async函数中await前的内容是同步的,await后的内容是异步的。
具体可看下面这个红绿灯的例子:
let redLight = document.querySelector('.red-light')
let yellowLight = document.querySelector('.yellow-light')
let greenLight = document.querySelector('.green-light')
function sleep(time){
return new Promise(res => { setTimeout(res,time)})
}
function changeLight(nowLight, nextLight){
console.log('in change light');
nowLight.style.backgroundColor = 'white'
if(nowLight.classList.contains('red-light') && nextLight.classList.contains('yellow-light')){
nextLight.style.backgroundColor = 'yellow'
} else if(nowLight.classList.contains('yellow-light') && nextLight.classList.contains('green-light')) {
nextLight.style.backgroundColor = 'green'
} else if(nowLight.classList.contains('green-light') && nextLight.classList.contains('red-light')) {
nextLight.style.backgroundColor = 'red'
} else {
throw('error combining')
}
}
async function main() {
while(1){
changeLight(yellowLight, greenLight)
await sleep(3000)
changeLight(greenLight, redLight)
await sleep(1000)
changeLight(redLight, yellowLight)
await sleep(2000)
}
}
main()
使用sleep函数可以将同步的函数改为异步执行的效果。