「面试梳理-JS」JS运行机制

158 阅读4分钟

谈谈js执行机制(异步)?

引言:

+ JS 是「单线程语言」,执行顺序 「自上而下」「逐行执行」(不能同时执行多行js代码)

+「JS可以操作DOM」,所以为了避免DOM渲染冲突,JS和DOM渲染共用同一个线程,即js执行时,DOM渲染会停止

js执行机制?

单线程?

异步和同步?

同步任务和异步任务?

异步应用场景?

异步的解决方案-event loop?

什么是执行栈和任务队列?

关于微任务和宏任务?

回调地狱?

提升-关于Promise?

提升-手写Promise?

提升-async和await和(Promise关系)?

1. js执行机制?

画板.jpg

** 执行机制:

1. 先执行「执行栈」中的 「同步任务」

2. 遇到「异步任务」,将「异步任务(回调函数)」放入「任务队列」中

3. 执行完「执行栈」中所有「同步任务」后,将「任务队列」中的「异步任务」放入「执行栈」中,开始执行。



** 遇到多个「异步任务」处理方式:

1. 先执行「执行栈」中的「同步任务」

2. 遇到「异步任务」,“ 将该「异步任务」提交给「异步进程处理」”,再决定是否需要放入「任务队列」

3. 执行完「执行栈」中所有「同步任务」后,将「任务队列」中的「异步任务」放入「执行栈」中,开始执行。
“执行完后,还会看「任务队列」中有没有新的异步任务,有,就会把他放入「执行栈」中继续执行”  -------事件循环

2. 单线程?

  • 单线程定义: 只有一个线程,同一时间,只能做一件事儿
  • 单线程缺点: 效率低, 可能会阻塞后面任务执行
  • 解决单线程缺点方案:用「异步」,提高效率

3. 异步?

  • 异步定义: 同时做多个「任务」,不会阻塞后面任务执行
  • 同步定义: 逐行执行,前一个「任务」结束,后一个任务才能执行,可能会阻塞后面任务执行
  • 异步的优缺点:
优点:  
1.不会阻塞后面任务的执行

缺点
1. 没有按照书写顺序执行, 可读性差

4. 同步任务和异步任务?

  • 同步任务:都在「主线程」上执行,形成「执行栈」
  • 异步任务:回调函数,放在「任务队列」中
js异步,是通过「回调函数」执行的

1. 定时器: setTimeout, setInterval
2. 资源加载: load
3. 事件: onclick

5. 异步应用场景?

需要等待的情况需要异步

  • a. 网络请求(ajax, 图片加载)
  • b. 定时任务(setTimeout, setInterval)

6. 异步的解决方案-event loop?

  • event loop定义:由于「执行栈」中不断获得「异步任务」、执行任务、再获得「异步任务」、再执行,这种机制被称为“事件循环”

  • event loop实现原理:

1. 将「异步任务」先放在「异步队列」中
2. 将「同步任务」执行完毕后
3. 「轮询执行」 查询「任务队列」中是否还有「异步任务」,将他们依次放入「执行栈」中执行

7. 什么是执行栈和任务队列?

  • 1.执行栈: 所有「同步任务」都在「主线程」上执行,这个「主线程」就是「执行栈」
  • 2.任务队列: 存放「异步任务」(包括微任务和宏任务)的消息队列,

8. 关于微任务和宏任务?

  • js 运行机制,执行顺序:同步任务 > 异步任务(微任务 > 宏任务)
  • promise特殊: Promise构造函数中函数体的代码立即执行(new Promise())
  • async 特殊:在出现await出现之前,其中的代码也是立即执行的。
  • 微任务:
1. Promise.then()
2. Promise.catch()
3. Promise.finally()
4. nextTick
5. MutationObserver
  • 宏任务:
1. setTimeout
2. setInterval
3. setImmediate
4. I/O 操作

9. Promise?

  • 三种状态: Pending、fulfilled、rejected
  • 初始状态: Pending
  • 状态变化:Pending -> fulfilled, Pending -> rejected
  • 注意事项:
1. 状态不可逆
2. Promise必须实现.then()这个方法
3. then 只是将callback 拆分了
4. then() 参数,可以接收两个函数
5. then() 返回的,必是一个Promise实例
  • 基本语法(.then())
const pro = new Promise((resolve, reject) => {
    resolve()
})
<!--第一个是成功回调,第二个是错误回调 -->
pro.then(() => {
    <!--这是成功回调-->
}, () => {
    <!--这是错误回调-->
} )
  • 异常捕获:统一捕获异常(catch)
<!--捕获程序的语法错误-->

pro.then(()=> {
    // 成功回调1
}).then(()=> {
    // 成功回调2
}).catch(() => {
    // 在这里统一捕获异常
})

// reject 携带参数,那么catch中就可以捕获逻辑错误

  • 多个串联(链式执行)
result1 = function () {}
result2 = function() {}
result1.then(params1 => {
    return result2
}).then((params2) => {
    console.log('-----')
}).catch((err) => {
    console.log(err)
})
  • Promise.all和Promise.race
1. 接收参数: promise对象的数组

2. Promise.all: 全部执行完后,统一执行success
Promise.all([]).then((datas) => {
    // datas是数组
})

3. Promise.race: 多个promise同时执行,只要一个完成,就执行success
Promise.race([]).then((data) => {
    // data是单个数据
})
10. async和await?
  • async/await: 最直接的同步写法
  • 写法注意:
1. 使用await,必须使用async
2. await后面跟的是Promise实例
3. 需要babel-polyfill