promise

2021/12/12 前端重点

# PromiseA+

# 浏览器的JS异步

# 宏任务/微任务

概念

  • js是单线程语言,执行顺序是单线程异步模型,所以有宏任务/微任务机制来处理异步操作
  • 三种机制任务:同步任务、(异步)宏任务、(异步)微任务
  • 宏任务:以下任务的回调函数
    1. I/O
    2. setTimeout
    3. setInterval
    4. requestAnimationFrame
    5. setImmediate
  • 微任务
    1. process.nextTick
    2. Promise.then / .catch / .finally
    3. async/await
    4. MutationObserver

  • 注意区分,setTimeout自身并不是宏任务,宿主环境将setTimeout的回调任务推入延迟队列。
  • 延迟队列中计时到了,才会将回调函数推入宏任务队列
  • 其他同理

# 浏览器多线程

  • JS引擎线程
  • GUI渲染线程(渲染页面)
  • 事件触发线程
  • 定时器触发线程
  • http请求线程
  • 其他线程

# 递归函数的风险

  • 递归函数是函数调用自身。
  • 递归函数是有风险的。因为递归函数会触发大量的栈帧堆积,让执行栈高度很高,可能会触发栈溢出。
  • 优化
    1. 尾调用优化
    2. 将递归写成同步函数(while)
    3. 递归函数放到异步函数里面(会一直变换任务队列,会比同步代码慢)

# 尾调用优化对比

  • 同样是异步任务,Promise微任务队列处理速度更快
console.time("run");
const factorial = async (num) => {
  let total = 1;
  let c = num;

  return new Promise((res) => {
    const deepHandler = () => {
      if (c === 1 || c === 0) {
        return res(c * total);
      }
      total = c * total;
      c = c - 1;
      // setTimeout(deepHandler); // run: 1:00.031 (m:ss.mmm)
      Promise.resolve().then(deepHandler); // run: 5.913ms
    };
    deepHandler();
  });
};

const s = 50000;
factorial(s).then((res) => {
  console.log(res);
  console.timeEnd("run");
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
  • 无限深度嵌套Promise.then也不快,因为这个一直在改变对象
console.time("run");
const factorial = async (num) => {
  let cPromise = Promise.resolve(num);
  while (num > 1) {
    num--;
    cPromise = cPromise.then(res => res * num);
  }
  return cPromise;
};

const s = 50000;
factorial(s).then((res) => {
  console.log(res);
  console.timeEnd("run"); // run: 15.457ms
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 宏任务

# nodeJS的异步

  • 文档 (opens new window)
  • nodejs只有轮询机制
  • process.nextTick为这一次轮询的末尾执行
  • setImmediate为下一次轮询开始执行
  • setTimeout加到下次轮询执行队列内
console.log(1);
setTimeout(() => console.log(5));
setImmediate(() => console.log(4));
process.nextTick(() => console.log(3));
console.log(2);

// 打印 1 2 3 4 5
1
2
3
4
5
6
7

# 方法

# Promise

构造器

  • 调用:new Promise((resolve, reject) => {})
  • 入参:Function
  • 返回:Promise对象

状态

  • Promise有三种状态,不可逆转
    pending -> fulfilled
    pending -> rejected

# then

  • 作用:Promise对象状态发生改变后的回调函数
  • 定义:promise.then(res => {}[, err => {}])
  • 入参:Function[, Function]
  • 返回:Promise
  • tip:第一个入参是状态变为fulfilling的回调,第二个入参是状态变为rejected的回调

# catch

  • 作用:promise状态变rejected或抛出异常时调用
  • 定义:promise.catch(err => {})
  • 定义2:promise.then(undefined, err => {})
  • 入参:Function
  • 返回:Promise

# finally

  • 作用:无论状态变成什么,最后都会执行的一个回调
  • 定义:promise.finally(callback)
  • 入参:Function
  • 返回:Promise

# 静态方法

# all

  • 作用:将多个Promise包装成一个Promise
  • 调用:Promise.all(promiseArr)
  • 入参:Iterator
  • 返回:Promise

  • .then的回调函数接受的参数是所有promise的resolve结果数组(有序)
  • .catch是任意一个入参promise被reject或抛出错误就会执行

# any

未完全支持

环境 版本
chrome 85
node 15.0

any

  • 作用:接收一个可迭代的promise集合,只返回第一个成功的promise结果

与race区别

  • race就是要第一个结果,无论是成功还是失败

# race

  • 作用:接收一个promise集合,采用第一个状态改变的promise的结果作为整体的结果
  • 定义:Promise.race(promiseArr)
  • 入参:Iterator
  • 返回:Promise

# allSettled

  • 作用:收集一个promise集合,等所有的promise状态都发生转变了,将所有的promise结果包装起来返回无论是成功还是失败
  • 定义:Promise.allSettled(promiseArr)
  • 入参:Iterator
  • 返回:Promise
  • tip:和all区别:all有失败就只返回失败的结果
  • tip:选择:promise之间有相互依赖选all;无依赖,只是并发选allSettled

# resolve

  • 作用:返回一个以给定值解析后的Promise对象
  • 定义:Promise.resolve(promise)
  • 入参:[Promise | thenable](当做本promise.resovle的返回) | any(被当做resolve的值)
  • 返回:Promise

入参

  • 入参有两种情况
    1. Promise/thenble
    2. other
  • Promise/thenable会被当做Promise.resolve(promise) 的返回处理。也就是直接入参当做返回值
  • other会被当做本Promise成功时resolve的值。也就是返回一个新的Promise,resolve(other)

# reject

  • 作用:reject返回一个带有拒绝原因的Promise对象
  • 定义:Promise.reject(reason)
  • 入参:any
  • 返回:Promise
上次更新: 11/1/2024