用生命谱写代码的赞歌

0%

JS 异步执行几个容易困惑的问题

setTimeout

1
2
3
4
5
6
7
8
9
function task() {
console.log('执行setTimeout')
}
setTimeout(() => {
task()
}, 3000)
console.log('执行console')
// 执行console
// 执行setTimeout

setTimeout 是一个异步的所以会先 执行 console 这个同步任务。如果修改代码如下,会发现执行时间远远超过预定的时间

1
2
3
4
setTimeout(() => {
task()
}, 3000)
sleep(10000)

执行过程如下:

  1. task 函数进入到 event table 里面注册计时
  2. 然后主线程执行 sleep 函数,比较慢。计时仍在继续
  3. 3 秒到了。 task 函数进入 event queue 但是主线程仍然没有走完
  4. 终于过了 10000ms 之后主线程走完了, task 函数进入到主线程执行。所以可以看出其真实的时间是远远大于 3 秒

说明几个容易困惑的问题

  1. setTimeout(fn, 0) , fn是不是立刻执行?

    不一定,要看主线程内的命令是否已经执行完了。这个任务会在主线程最早可得的空闲时间执行,就是主线程的任务执行结束之后立马执行。

    HTML5 标准规定了 setTimeout() 的第二个参数的最小值(最短间隔),不得低于 4 毫秒,如果低于这个值,就会自动增加。在此之前,老版本的浏览器都将最短间隔设为 10 毫秒。另外,对于那些 DOM 的变动(尤其是涉及页面重新渲染的部分),通常不会立即执行,而是每 16 毫秒执行一次。

  2. Ajax 请求是否异步?

    Ajax 异步请求内容的时候是异步的,当请求完成后,会触发请求完成的事件,然后把回调函数放入 callback queue ,等到主线程执行该回调函数时还是单线程的。

  3. 界面渲染线程是单独开辟的线程,是不是 DOM 一变化,界面就立刻重新渲染?

    如果 DOM 一变化,界面就立刻重新渲染,效率必然很低,所以浏览器的机制规定界面渲染线程和主线程是互斥的,主线程执行任务时,浏览器渲染线程处于挂起状态。