JavaScript执行任务的机制
大家都知道,JavaScript是一门单线程语言。所以JavaScript执行任务只能一个一个按顺序来执行。
但是这有个问题,如果任务1执行时间过长,后边的任务必须得等着任务1执行完成后,才能够轮到它。这样必然会出现网页加载停留时间增加。
所以有了异步任务
什么是异步任务:
- 准备要做一件事情,但不是立刻去做这件事情,而是需要等一段时间再去做。这样的话,我们不会傻傻的等待他做,而是先去忙别的事情。
在JavaScript中,最基础的异步是setTimeout和setInterval函数。
可以去看mdn对setTimeout的解析:window.setTimeout
总结一下,它可以改变一个队列函数的执行顺序。
JavaScript函数的执行时机
函数执行的时机不同,运行结果也不同。
举个栗子
同步
栗子1:
let a = 1
function fn() {
console.log(a)
}
请问: 打印出来的值是多少?
答案: 不知道, 因为没有执行fn啊
栗子2:
let a = 1
function fn(){
console.log(a)
}
a = 2
fn()
请问: 打印出来的值是多少?
答案: 2,
执行步骤:
- 声明一个变量a和一个函数fn
- 将2赋值给a
- 调用fn函数
栗子3:
let a = 1
function fn(){
console.log(a)
}
fn()
a = 2
请问: 打印出来的值是多少?
答案: 1,
执行步骤:
- 声明一个变量a和一个函数fn
- 调用fn函数
- 将2赋值给a
上面3个例子就体现了同步任务执行步骤,就是一步一步的按顺序执行。
异步
再来举栗子!
let a = 1
function fn(){
setTimeout(()=>{
console.log(a)
},0)
}
fn()
a = 2
请问:打印出来的a是多少?
答案: 2,
执行步骤:
- 声明变量a和函数fn
- 把 1 赋值给 a,
- 执行fn()
- 因为有 setTimeout 所以要等到同步任务执行完后,再去执行
- 把 2 赋值给 a
- 执行 setTimeout() 打印出 a的值:2,
经典面试题
let i = 0
for(i = 0; i<6; i++){
setTimeout(()=>{
console.log(i)
},0)
}
请问: 打印出的 i 是多少?
很简单啊,不是0、1、2、3、4、5吗?
错啦! 正确答案: 打印出 6个6
解释: 因为 setTimeout 是异步的, 需要等会同步的执行完再执行, 所以当for循环执行完毕后,i的值是6,然后再执行setTimeout,当然是执行6次哦,所以答案是 6个6.
怎么才能输出0、1、2、3、4、5呢?
有很多方法:
方法1: 把let写在for循环里面,这样可以单纯为每个i创造一个块级作用域,也就是复制6个i。
for(let i = 0; i<6; i++){
setTimeout(()=>{
console.log(i)
},0)
}
方法2: 利用立即执行函数
let i = 0
for(i = 0; i<6; i++){
!function(i){
setTimeout(()=>{
console.log(i)
},0)
}(i)
}
方法3: 利用 setTimeout 的第三个参数
let i = 0
for(i = 0; i<6; i++){
setTimeout((i)=>{
console.log(i)
},0,i)
}