宏任务异任务

149 阅读3分钟

面试题2

for(var i = 0; i < 3; i++) {
    settimeout(() => {
        console.log(i)		//结果是?
    },0)
}

答案是全都是3 这个有关于宏任务的异步 settimeout是一个异步的任务 只有在执行反for循环属于主线程的代码 这个主线程任务之后 才会在异步任务中拿到代码开始执行这个settimeout的任务 所以最后打印的结果都是3 所以 解决方法?

解决方案就是把 var 改成 let 或者是在for循环中创建出一个闭包

for(let i = 0; i < 3; i++) {
    settimeout(() => {
        console.log(i)		
    })
}
()()

for(var i = 0; i < 3; i++) {
    (function(i){
        settimeout(() => {
            console.log(i)		
	})
    })(i)
}

这道题其实讲到这里 我还是不太懂得感觉 就是说不是很理解为什么用了let之后就可以了 所以又去看了一下他说的关于 宏任务的异步

了解这些东西之前 先知道一个叫做事件循环的东西

我们知道其实由于 js 是单线程 所以就催生出了同步和异步的这个观念 原因就是js无法忍受等待一个个任务的完成(读取文件 读取数据库......) 在等待异步任务准备的同时,JS引擎去执行其他同步任务,等到异步任务准备好了,再去执行回调。这种模式的优势显而易见,完成相同的任务,花费的时间大大减少,这种方式也被叫做非阻塞式

这里会有一个 通知的过程 而这个过程就叫做事件循环 把异步任务的回调部分交给事件循环,等时机合适交还给JS线程执行。

为啥子叫做循环?

什么是宏任务和微任务?

对于事件循环 根据队列中任务的不同,分为宏任务和微任务。

为什么要有宏任务和微任务?

然后我就总结了一下 宏任务和微任务

由于事件循环是由队列组成 所以会遵循先进先出的理念 但是在实际运算中时会出现紧急事件发生的 所以打比方就是宏任务是好学生 微任务就是坏学生 坏学生会插队 这样微任务中所做的状态修改,在下一轮事件循环中也能得到同步。

就是由于宏任务中的settimeout会有一个误区

setTimeout的回调不一定在指定时间后能执行。而是在指定时间后,将回调函数放入事件循环的队列中

如果时间到了,JS引擎还在执行同步任务,这个回调函数需要等待;如果当前事件循环的队列里还有其他回调,需要等其他回调执行完。

另外,setTimeout 0ms 也不是立刻执行,它有一个默认最小时间,为4ms

所以最后我的理解就是 由于settimeout中的那个for循环执行时间很短 小于 4ms 所以里面的异步任务就会等待for循环结束之后再来执行这个函数 所以就会出现所谓的 3 被打印了三次

其实答案是每一次for循环的时候,setTimeout都执行一次但是里面的函数没有被执行,而是被放到了任务队列里,等待执行。只有主线上的任务执行完,才会执行任务队列里的任务。

然后后面又找到了一篇文章 终于找到答案了

for(let i = 0; i < 3; i++) {
    settimeout(() => {
        console.log(i)		
    })
}

for(var i = 0; i < 3; i++) {
    (function(i){
        settimeout(() => {
            console.log(i)		
	})
    })(i)
}

let解决方案详解

window. Window

.proxy