Skip to content

JS执行机制

经典面试题

js
console.log(1)
setTimeout(() => {
    console.log(2)
}, 1000)
console.log(3)
// 问:输出的顺序是什么
// 答1, 3, 2

延时了1秒钟, 所以是132, 合理

js
console.log(1)
setTimeout(() => {
    console.log(2)
}, 0)
console.log(3)
// 问:输出的顺序是什么
// 答1, 3, 2

为什么延时0秒, 不应该是立即执行么, 怎么还是132?

线程

JavaScript语言的一大特点就是单线程, 也就是说, 同一时间只能做一件事

:::note 这是因为JavaScript这门脚本语言诞生的使命所致的

JavaScript是为处理页面中用户的交互, 以及操作DOM而诞生的.比如我们对某个DOM元素进行添加和删除操作, 不能同时进行.应该先添加, 之后再删除

单线程就意味着, 所有任务需要排队, 前一个任务结束, 才会执行后一个任务.这样所导致的问题是:

如果JS执行的时间过长, 就会造成页面渲染不连贯, 导致页面渲染加载堵塞感

为了解决这个问题, 利用多核CPU的算力, Html5提出Web Worker标准, 运行JavaScript脚本创建多个线程.于是, JS中出现了同步异步 :::

同步

前一个任务结束后再执行后一个任务, 程序的执行顺序与任务的排队顺序是一致的, 同步的.举个例子

洗米花费5分钟, 煮饭花费40分钟, 饭熟了才去切菜花费5分钟, 炒菜花费30分钟, 一共花费了1个小时30分钟.看不懂?上图!

异步

你在做一件事情时, 因为这件事情会花费很长时间, 在做这件事的同时, 可以去处理其他事情.举个例子

洗米花费5分钟, 煮饭花费40小时, 饭还有35分钟熟的时候, 去切菜花费5分钟, 炒菜花费30分钟, 这时饭刚好熟了, 一共花费了45个小时.看不懂?上图!

本质

同步和异步本质就是执行顺序的不同

同步任务

同步任务都是在主线程上执行, 形成一个执行栈

异步任务

JS的异步是通过回调函数实现的

一般而言, 异步任务有以下3种类型

  1. 普通事件, 如click, resize
  2. 资源加载, 如load, error
  3. 定时器, 包括setInterval, setTimeout

异步任务相关添加到任务队列中(任务队列也称为消息队列)

机制

  1. 先执行执行栈中的同步任务
    1. 输出1
    2. 输出3
  2. 异步任务放入消息队列中
    1. 记录setTimeout(console.log(2), 0)
  3. 一旦执行栈的所有同步任务执行完毕, 系统就会按次序读取消息队列中的异步任务, 于是被读取的异步任务结束等待状态, 进入执行栈, 开始执行
    1. 输出2

由于主线程不断的重复获取任务, 执行任务, 再获取任务, 再执行, 所以这种机制被称为事件循环(event loop)

72c5656c1e15a695fb3a3a96ec3381cd2487fb2e