# Promise & async await

# 顺序执行最佳实践

  • 尽量使用 async await, 异步函数同步写法, 完全解决了回调地狱问题
  • 对于异常捕获的两种看法

# 使用try catch(推荐)

  • 既然使用了 await 就抛弃链式用法, 配合分支逻辑使用 if else, try catch
  • 异常机制的一个要点是集中捕获再处理上报
const fn = async () => {
  try {
    const r1 = await fn1();
    const r2 = await fn2(r1.xxx);
    const r3 = await fn3(r2.xxx);
    const user = { ...r1, ...r2, ...r3 }

    return user
  } catch(e) {
    console.error(e)
    return null
  }
}

# 使用 await 配合 .catch() + if () 判断 response, or .catch 里面 throw or Promise 里面 reject(err)

const response1 = await axios("/xxx").catch(handleError) 
if (!response1) return
// or
const response2 = await axios("/xxx").catch(err => throw err) 

# 并发执行最佳实践

  • 并发不能统一处理异常
const getData1 = this.$axios.$get("/xxx").catch(() => {});
const getData2 = this.$axios.$get("/xxx").catch(() => {});
const [res, res2] = await Promise.all([getData1, getData2]).finally();
if (res) {
  // do something...
}
if (res2) {
  // do something...
}

# 利用 Promise 做并发限制

const asyncTask = (t, taskName) => {
  return new Promise(resolve => {
    console.log(`开始执行 ${taskName} ~~~`);
    setTimeout(() => {
      console.log(`${taskName} 结束啦 !!!`);
      resolve()
    }, t);
  })
}

const taskList = [
  () => asyncTask(100, 'task1'),
  () => asyncTask(300, 'task2'),
  () => asyncTask(500, 'task3'),
  () => asyncTask(200, 'task4'),
  () => asyncTask(700, 'task5'),
  () => asyncTask(400, 'task6'),
]

/**
 * 异步任务并发限制
 * @param {*} tasks 任务总数
 * @param {*} limit 最大并发限制数量
 */
const limmitTaskPool = async (tasks, limit) => {

  const taskPool = new Set()
  for (const task of tasks) {
    // 执行
    const promise = task()
    // 添加到任务池中
    taskPool.add(promise)
    // 异步任务,会在同步任务执行完再执行, 删除已执行完的任务
    promise.then(() => taskPool.delete(promise))
    // 任务池的数量大于等于并发限制
    if (taskPool.size >= limit) {
      // 超出限制,需要先执行一个最快的异步任务(等待异步任务执行完删除自身空出任务池),再执行下一个任务
      await Promise.race(taskPool)
    }
  }
  // 这一步是为了让剩下所有任务执行完再返回, 不需要获取所有任务执行完的状态可以省略
  return Promise.all(taskPool)
}

limmitTaskPool(taskList, 2).then(() => console.log('所有任务全部执行完毕!'))

# promiseA+

  • promise.all 可以让多个异步的接口并发执行,在接口数量很多的时候大大加快请求的速度
  • 缺点:一个接口特别慢,其他接口也要等着他
  • 每个 promise 实例单独赋值,加上 .catch(e => e) , 不然一个接口错误其他也错误
then 里面有几个概念,
promise2 .then调用会返回一个新的promise,所以每次调用都用一个新的promise2接收他。
x 是这次调用的返回值
在then 里面判断state状态,执行 resolvePromise(promise2,x,resolve,reject)
链式调用就是每次都把结果(函数或value)当成参数去调用,
resolvePromise 里判断判断是值还是函数,是函数就在调用,是值就resolve(x)


    class Promise {
      constructor(executor) {
        this.state = 'pending';
        this.value = undefined;
        this.reason = undefined;
        this.onResolvedCallbacks = [];
        this.onRejectedCallbacks = [];
        let resolve = value => {
          if (this.state === 'pending') {
            this.state = 'fulfilled';
            this.value = value;
            this.onResolvedCallbacks.forEach(fn => fn());
          }
        };
        let reject = reason => {
          if (this.state === 'pending') {
            this.state = 'rejected';
            this.reason = reason;
            this.onRejectedCallbacks.forEach(fn => fn());
          }
        };
        try {
          executor(resolve, reject);
        } catch (err) {
          reject(err);
        }
      }
      then(onFulfilled, onRejected) {
        // onFulfilled如果不是函数,就忽略onFulfilled,直接返回value
        onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
        // onRejected如果不是函数,就忽略onRejected,直接扔出错误
        onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err };
        let promise2 = new Promise((resolve, reject) => {
          if (this.state === 'fulfilled') {
            // 异步
            setTimeout(() => {
              try {
                let x = onFulfilled(this.value);
                resolvePromise(promise2, x, resolve, reject);
              } catch (e) {
                reject(e);
              }
            }, 0);
          };
          if (this.state === 'rejected') {
            // 异步
            setTimeout(() => {
              // 如果报错
              try {
                let x = onRejected(this.reason);
                resolvePromise(promise2, x, resolve, reject);
              } catch (e) {
                reject(e);
              }
            }, 0);
          };
          if (this.state === 'pending') {
            this.onResolvedCallbacks.push(() => {
              // 异步
              setTimeout(() => {
                try {
                  let x = onFulfilled(this.value);
                  resolvePromise(promise2, x, resolve, reject);
                } catch (e) {
                  reject(e);
                }
              }, 0);
            });
            this.onRejectedCallbacks.push(() => {
              // 异步
              setTimeout(() => {
                try {
                  let x = onRejected(this.reason);
                  resolvePromise(promise2, x, resolve, reject);
                } catch (e) {
                  reject(e);
                }
              }, 0)
            });
          };
        });
        // 返回promise,完成链式
        return promise2;
      }
    }
    function resolvePromise(promise2, x, resolve, reject) {
      // 循环引用报错
      if (x === promise2) {
        // reject报错
        return reject(new TypeError('Chaining cycle detected for promise'));
      }
      // 防止多次调用
      let called;
      // x不是null 且x是对象或者函数
      if (x != null && (typeof x === 'object' || typeof x === 'function')) {
        try {
          // A+规定,声明then = x的then方法
          let then = x.then;
          // 如果then是函数,就默认是promise了
          if (typeof then === 'function') {
            // 就让then执行 第一个参数是this   后面是成功的回调 和 失败的回调
            then.call(x, y => {
              // 成功和失败只能调用一个
              if (called) return;
              called = true;
              // resolve的结果依旧是promise 那就继续解析
              resolvePromise(promise2, y, resolve, reject);
            }, err => {
              // 成功和失败只能调用一个
              if (called) return;
              called = true;
              reject(err);// 失败了就失败了
            })
          } else {
            resolve(x); // 直接成功即可
          }
        } catch (e) {
          // 也属于失败
          if (called) return;
          called = true;
          // 取then出错了那就不要在继续执行了
          reject(e);
        }
      } else {
        resolve(x);
      }
    }


    var p = new Promise(function (resolve, reject) {
      setTimeout(function () {
        debugger;
        resolve(3)
      }, 1000)
    });
    p
      .then((r) => {
        console.log(r, 'haola haola')
        return 1;
      })
      .then((res) => {
        //3
        console.log(res)
      })

# promise.all

Promise._All = function (promises) {
  let arr = [],
    count = 0
  return new Promise((resolve, reject) => {
    promises.forEach((item, i) => {
      Promise.resolve(item).then(res => {
        arr[i] = res
        count += 1
        if (count === promises.length) resolve(arr)
      }, reject)
    })
  })
}