Promise

Promise

一种异步编程解决方案。避免了回调地狱现象的发生

1、JS中异步编程的解决方案

  • 传统方案
    • 单纯使用回调函数【容易产生深层次的回调嵌套,形成回调地狱现象】
  • 新方案
    • 生成器
    • Promise【支持链式调用,解决了回调地狱问题】
    • async+await
let p = new Promise((resolve, reject) => {
	// new Promise的回调是 同步执行
	resolve('hello')
})
console.log(p);

2、Promise的状态

Promise的状态 其实是Promise实例上的一个属性:PromiseState

2.1、Promise的三种状态

  • pending: 未决定的/等待中
  • resolved/fulfilled: 成功
  • rejected: 失败

2.2、Promise的状态变化

  • 只可能是pending变化为fulfilled;或者 pending变化为rejected。 【不可能是rejected和fulfilled相互变化】
  • Promise的状态变化只可能发生一次
  • PromiseState为内置属性,不能改变
  • 只能通过resolve() 或者 reject() 或者 throw抛出错误 改变Promise 状态PromiseState

3、Promise的值

Promise的值 :Promise实例上的另一个属性:PromiseResult, 保存着异步任务成功或者失败的结果

4、Promise的基本工作流程

Promise_第1张图片
then方法的第二个回调函数 处理的是reject结果

5、Promise API

5.1、Promise构造函数原型prototype上的api:

  • Promise.resolve(): 将一个值封装为一个Promise对象,即是返回一个Promise对象,【不需要再new Promise】
// 如果resolve的参数为 非Promise类型, 则返回结果为成功的promise对象
// 如果resolve的参数为Promise类型, 则返回结果为  由参数的promise结果决定
let p = Promise.resolve('hello')
//  let p2 = Promise.resolve(new Promise((resolve, reject) => {
//   reject('error')
//  }))
console.log(p);
  • Promise.reject(value: any): 始终返回失败的promise
  • Promise.all(promiseArr): promiseArr数组参数的每个promise元素都成功,返回的结果才是成功的promise。
  • Promise.allSettled(promiseArr): promiseArr数组参数的每个promise元素都改变了状态
  • Promise.race(promiseArr): 返回结果状态和结果值由 数组参数promiseArr最先执行的promise决定
  • Promise.any(promiseArr): 只要有一个promise的结果为成功,则返回结果状态就是成功的promise

5.2、new Promise() 实例对象上的api

const p = new Promise() 下面就用p.xxx()

  • p.then(onResolved, onRejected)
  • p.catch(onRejected): 只有失败的回调函数onRejected。底层使用的还是then方法
  • p.then().then().then()…then().catch() : 在then的链式(promise链)调用的最后调用ctach,形成异常穿透现象。
  • p.finally(): 注意: 无参回调

中断promise链即中断p.then()的链式调用的唯一方法:返回一个pending状态的promise

p.then((res)=>{
	conssole.log(res)
	return new Promise(() => {})
})

6、自定义封装Promise

class Promise {
  constructor(executor) {
    // 添加属性
    this.PromiseState = "pending";
    this.PromiseResult = null;
    // 保存then方法的回调
    // 保存为数组:解决 可以多次调用then的问题。
    // 如果保存为对象,则对此调用then,只会执行最后一次保存的回调
    // this.callBack = {};
    this.callBacks = [];
    const _this = this;
    // resolve 函数
    function resolve(data) {
      // 这里面的this 默认指向window

      // 保证promise的状态只能修改一次
      if (_this.PromiseState !== "pending") return;
      // 1. 修改Promise对象的状态
      _this.PromiseState = "fulfilled";
      // 2. 修改Promise对象的结果值
      _this.PromiseResult = data;

      // 异步任务 改变完状态  再执行then对应的回调
      // 调用then成功的回调
      setTimeout(() => {
        // then中的回调是异步执行的
        _this.callBacks.forEach((callBack) => {
          callBack.onResolved && callBack.onResolved(data);
        });
      });
    }
    // reject 函数
    function reject(data) {
      if (_this.PromiseState !== "pending") return;
      _this.PromiseState = "rejected";
      _this.PromiseResult = data;

      // then中的回调是异步执行的
      setTimeout(() => {
        _this.callBacks.forEach((callBack) => {
          callBack.onRejected && callBack.onRejected(data);
        });
      });
    }

    // try...catch 捕获new Promise()回调里面的throw
    try {
      // 同步调用执行器函数
      executor(resolve, reject);
    } catch (error) {
      reject(error);
    }
  }
  then(onResolved, onRejected) {
    const _this = this;
    // 添加异常穿透
    if (typeof onRejected !== "function") {
      onRejected = (reason) => {
        throw reason;
      };
    }
    // 给成功回调添加默认值
    if (typeof onResolved !== "function") {
      onResolved = (value) => value;
    }
    return new Promise((resolve, reject) => {
      function callBack(fnType) {
        // try catch  处理throw的情况
        try {
          // 获取then回调函数的执行结果
          let res = fnType(_this.PromiseResult);
          if (res instanceof Promise) {
            // 如果是Promise类型的对象
            res.then(
              (r) => {
                resolve(r);
              },
              (e) => {
                reject(e);
              }
            );
          } else {
            resolve(res);
          }
        } catch (error) {
          reject(error);
        }
      }
      if (this.PromiseState === "fulfilled") {
        // then中的回调是异步执行的
        setTimeout(() => {
          callBack(onResolved);
        });
      }
      if (this.PromiseState === "rejected") {
        // then中的回调是异步执行的
        setTimeout(() => {
          callBack(onRejected);
        });
      }
      // pending: 处理异步任务
      if (this.PromiseState === "pending") {
        // 保存回调函数: 为了再其他作用域下的  resolve或者reject  可以调用then回调
        this.callBacks.push({
          onResolved: function () {
            // 给异步任务添加promise的返回结果
            callBack(onResolved);
          },
          onRejected: function () {
            callBack(onRejected);
          },
        });
      }
    });
  }
  catch(onRejected) {
    return this.then(undefined, onRejected);
  }
  static resolve(value) {
    return new Promise((resolve, reject) => {
      if (value instanceof Promise) {
        value.then(
          (r) => {
            resolve(r);
          },
          (e) => {
            reject(e);
          }
        );
      } else {
        resolve(value);
      }
    });
  }
  static reject(reason) {
    return new Promise((resolve, reject) => {
      reject(reason);
    });
  }
  static all(promises) {
    return new Promise((resolve, reject) => {
      let count = 0;
      let savePromisesResult = [];
      for (let i = 0; i < promises.length; i++) {
        promises[i].then(
          (r) => {
            count++;
            // 给savePromisesResult添加每个promise的结果时,不能使用push
            // push不能保证顺序
            savePromisesResult[i] = r;
            if (count === promises.length) {
              resolve(savePromisesResult);
            }
          },
          (e) => {
            reject(e);
          }
        );
      }
    });
  }
  static race(promises) {
    return new Promise((resolve, reject) => {
      for (let i = 0; i < promises.length; i++) {
        promises[i].then(
          (r) => {
            resolve(r);
          },
          (e) => {
            reject(e);
          }
        );
      }
    });
  }
}

7、async和await

异步编程的另一种解决方案,将异步写法 同步化

1、async函数

  • async函数始终返回一个promise对象

2、await表达式

  • await右侧的表达式一般为promise对象,但也可以是其他的值
  • await promise; 返回的是promise成功的值
  • await 非promise; 返回的是这个非promise

3、注意:

  • await表达式 必须写在async函数里,但async函数可以没有await表达式
  • 如果await的promise失败了,就会抛出异常, 需要try…catch捕获处理

其他

1、JS异步之宏队列和微队列

JS异步都会存放到队列中。微队列里的异步会优先执行完,再执行宏队列的异步。

1.1、宏队列

  • 宏队列的每个回调被称为宏任务
  • 宏任务有:定时器回调、DOM事件回调、ajax回调

1.2、微队列

  • 微队列的每个回调被称为微任务
  • 微任务有: promise的回调、MutationObserver的回调

1.3、JS引擎的执行顺序

  • 先执行所有的初始化同步任务代码
  • 每次准备执行第一个宏任务前, 都需要将所有的微任务执行一遍

你可能感兴趣的:(web前端,javascript)