前端入门11 -- JavaScript之Promise

回调函数

  • 回调函数分为两种类型,分别为同步回调与异步回调;
  • 同步回调:会立即执行,完全执行完了才结束,不会放入回调队列中;
  • 异步回调:不会立即执行,会放入回调队列中 将来执行;
  
  • 遍历回调属于同步回调,立即执行;
  • 定时器中的回调属于异步回调,不会立即执行;

常见的内置错误

  • Error:所有错误的父类型;
  • ReferenceError:引用变量不存在;
  • TypeError:数据类型不正确;
  • RangeError:数据值不在其所允许的范围之内;
  • SyntaxError:语法错误;
  
错误的处理
  • 错误处理的方式有两种:捕获错误和抛出错误;
  • 捕获错误:try ... catch

  • 抛出错误:throw error,错误由调用者进行处理;
  

Promise

  • Promise是JS中进行异步编程的一种解决方案;
  • 从语法上来说,Promise是一个构造函数;
  • 从功能上来说,Promise对象用来封装一个异步操作并可以获取其结果;
Promise的状态
  • 初始化状态为pending;
    • pending变为resolved;
    • pending变为reiected;
  • 一个Promise对象,其状态只能改变一次,无论变为成功还是失败,都会有一个结果数据,成功的结果数据一般称为value,失败的结果数据一般称为reason;
  • Promise执行的基本流程如下:
image.png
Promise的基本使用
  • 首先创建Promise实例对象;
  • 在执行器中执行异步任务;
  • 获取异步任务的处理结果;
  
Promise的优点
  • 首先Promise指定回调函数的方式更加灵活;
    • 纯回调函数形式,指定回调函数必须在异步任务执行之前;
    • Promise形式,指定回调函数在执行异步任务前后均可以,更加灵活;
  • 其次Promise支持链式调用,可以解决回调地狱问题,终极解决方案为:async/await;
  
  
Promise常见API
image.png
  
  • Promise.resolve(value):返回值为一个新的promise,参数value值可以是promise,可以是非promise
    • 当value为非promise时,那么新promise的状态结果为resolve成功;
    • 当value为promise时,那么新promise的状态结果为value的状态结果;
  • Promise.reject(value):返回值为一个新的promise,其状态结果为reject失败;
  • Promise.all(promise数组):返回值为一个新的promise,其状态结果为:
    • 当promise数组中存在一个状态失败的,那么新promise的状态结果为失败;
    • 当promise数组中都成功,那么新promise的状态结果为一个数组集合值;
  • Promise.race(promise数组):返回值为一个新的promise,其状态结果为:promise数组中先返回状态结果的promise的状态结果;

Promise的使用注意事项

  • promise的状态改变分为三种情况:
    • 执行成功resolve(value),pending --> resolve;
    • 执行失败reject(reason),pending --> reject;
    • 抛出异常 throw error,pending --> reject;
  • 一个promise对象,可以指定多个状态回调,且多个状态回调都会执行;
  
  • 如何控制改变promise状态指定回调函数的先后顺序?
    • 常规情况下:先指定回调函数,再改变promise状态,执行回调函数;
  
  • promise.then()会返回一个新的promise对象,此promise的状态结果由什么决定?
    • 由then()指定的回调函数执行的结果决定;
    • then()指定的回调函数,没有返回值,则新的promise对象状态变成resolve,value值为undefined;
    • then()指定的回调函数,返回非promise的任意值value,则新的promise对象状态变成resolve,会执行成功的回调,且获取value值;
    • then()指定的回调函数,抛出异常,则新的promise对象状态变成reject,会执行失败的回调;
    • then()指定的回调函数,返回另一个新的promise,则此promise的状态结果会成为新promise的状态结果;
  
  • promise如何串联多个操作任务?
    • promise.then()可返回一个新的promise;
    • promise.then()的链式调用可串联多个同步/异步任务;
  
image.png
  • promise的异常传透:
    • 当使用promise的then链式调用时,可以再最后指定失败的回调;
    • 前面任何操作出现了异常,都会传到最后失败的回调;
  
  • . catch失败处理,上面没有失败的处理,就会执行. catch中的代码,没有失败的处理等价于reason => { throw reason },抛出了异常,然后一直往下传递异常,最终会执行. catch中的代码;
  • 如何中断promise链?
    • 当使用promise的then链式调用时,在中间中断,不再调用后面的回调函数;
    • 方案:在回调函数中返回一个pending状态的promise对象;
  
  • 注意.catch()函数也会返回一个新的promise对象;

自定义Promise

  • 函数对象,代码如下:
//自定义Promise函数模块
(function (window) {

  const PENDING = 'pending';
  const RESOLVED = 'resolved';
  const REJECTED = 'rejected';

  //Promise的构造函数
  function Promise(excutor) {
    const self = this;
    //promise状态 初始化为pending
    self.status = PENDING;
    //promise异步操作的结果数据
    self.data = undefined;
    //promise的回调函数
    self.callbacks = [];

    function resolve(value) {
      if (self.status !== PENDING) {
        return;
      }
      //将状态改成resolved
      self.status = RESOLVED;
      self.data = value;
      //若存在callback回调函数,则立即异步执行回调函数
      if (self.callbacks.length > 0) {
        setTimeout(() => {
          self.callbacks.forEach(element => {
            element.onResolved(value);
          });
        });
      }
    }

    function reject(reason) {
      if (self.status !== PENDING) {
        return;
      }
      self.status = REJECTED;
      self.data = reason;
      if (self.callbacks.length > 0) {
        setTimeout(() => {
          self.callbacks.forEach(element => {
            element.onRejected(reason);
          });
        });
      }
    }

    try {
      excutor(resolve, reject);
    } catch (error) {
      //捕获异常了 执行reject方法 状态成为rejected
      reject(error);
    }
  }

  //Promise原型上的函数方法
  Promise.prototype.then = function (onResolved, onRejected) {
    //当前promise对象
    const self = this;

    onResolved = typeof onResolved === 'function' ? onResolved : value => value;
    onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason };

    //返回一个新的promise对象
    return new Promise((resolve, reject) => {
      //处理函数
      function handle(callback) {
        //新promise对象的状态结果 由当前promise对象的状态结果决定
        //1.当前promise结果为抛出异常,则新的promise结果为失败,值为异常error
        //2.当前promise结果为非promise,则新的promise结果为成功,值为异常value
        //3.当前promise结果为promise,则新的promise结果为promise的结果
        try {
          const result = callback(self.data);
          if (result instanceof Promise) {
            result.then(resolve, reject);
          } else {
            resolve(result);
          }
        } catch (error) {
          reject(error);
        }
      }

      if (this.status === RESOLVED) {
        //立即异步执行 当前promise对象 成功的回调函数
        setTimeout(() => {
          handle(onResolved);
        });
      } else if (self.status === REJECTED) {
        setTimeout(() => {
          handle(onRejected);
        });
      } else {
        //将成功和失败的回调函数保存到callbacks容器中
        self.callbacks.push({
          onResolved(value) {
            handle(onResolved);
          },
          onRejected(reason) {
            handle(onRejected);
          }
        });
      }
    });

    if (self.status === PENDING) {
      //保存回调方法 到一个对象中
      self.callbacks.push({
        onResolved,
        onRejected
      })
    } else if (self.status === RESOLVED) {
      setTimeout(() => {
        resolve(self.data)
      });
    } else {
      setTimeout(() => {
        reject(self.data);
      });
    }

  }

  Promise.prototype.catch = function (onRejected) {
    Promise.prototype.then(undefined, onRejected);
  }

  //Promise函数对象方法
  Promise.resolve = function (value) {
    //返回一个状态结果为 成功或失败的promise对象
    return new Promise((resolve, reject) => {
      if (value instanceof Promise) {
        value.then(resolve, reject);
      } else {
        resolve(value);
      }
    })
  }

  Promise.reject = function (reason) {
    //返回一个状态结果为失败的promise对象
    return new Promise((resolve, reject) => {
      reject(reason);
    })
  }

  Promise.all = function (promises) {
    //保存所有成功的value的数组
    const values = new Array(promises.length);
    //记录成功promise的数量
    let resloveCount = 0;
    return new Promise((reslove, reject) => {
      promises.forEach((p, index) => {
        p.then(
          value => {
            resloveCount++;
            values[index] = value;
            if (resloveCount === promises.length) {
              reslove(values);
            }
          },
          reason => {
            reject(reason);
          }
        )
      });
    });
  }

  Promise.race = function (promises) {
    return new Promise((resove, reject) => {
      promises.forEach((p, index) => {
        p.then(
          value => {
            resove(value);
          },
          reason => {
            reject(reason);
          }
        )
      });
    });
  }

  //向外暴露Promise的构造函数
  window.Promise = Promise;
})(window)
  • 类Class对象,代码如下:
//自定义Promise函数模块
(function (window) {

  const PENDING = 'pending';
  const RESOLVED = 'resolved';
  const REJECTED = 'rejected';

  class Promise {
    constructor(excutor) {
      //Promise的构造函数
      const self = this;
      //promise状态 初始化为pending
      self.status = PENDING;
      //promise异步操作的结果数据
      self.data = undefined;
      //promise的回调函数
      self.callbacks = [];

      function resolve(value) {
        if (self.status !== PENDING) {
          return;
        }
        //将状态改成resolved
        self.status = RESOLVED;
        self.data = value;
        //若存在callback回调函数,则立即异步执行回调函数
        if (self.callbacks.length > 0) {
          setTimeout(() => {
            self.callbacks.forEach(element => {
              element.onResolved(value);
            });
          });
        }
      }

      function reject(reason) {
        if (self.status !== PENDING) {
          return;
        }
        self.status = REJECTED;
        self.data = reason;
        if (self.callbacks.length > 0) {
          setTimeout(() => {
            self.callbacks.forEach(element => {
              element.onRejected(reason);
            });
          });
        }
      }

      try {
        excutor(resolve, reject);
      } catch (error) {
        //捕获异常了 执行reject方法 状态成为rejected
        reject(error);
      }
    }
    //Promise原型上的函数方法
    then(onResolved, onRejected) {
      //当前promise对象
      const self = this;

      onResolved = typeof onResolved === 'function' ? onResolved : value => value;
      onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason };

      //返回一个新的promise对象
      return new Promise((resolve, reject) => {
        //处理函数
        function handle(callback) {
          //新promise对象的状态结果 由当前promise对象的状态结果决定
          //1.当前promise结果为抛出异常,则新的promise结果为失败,值为异常error
          //2.当前promise结果为非promise,则新的promise结果为成功,值为异常value
          //3.当前promise结果为promise,则新的promise结果为promise的结果
          try {
            const result = callback(self.data);
            if (result instanceof Promise) {
              result.then(resolve, reject);
            } else {
              resolve(result);
            }
          } catch (error) {
            reject(error);
          }
        }

        if (this.status === RESOLVED) {
          //立即异步执行 当前promise对象 成功的回调函数
          setTimeout(() => {
            handle(onResolved);
          });
        } else if (self.status === REJECTED) {
          setTimeout(() => {
            handle(onRejected);
          });
        } else {
          //将成功和失败的回调函数保存到callbacks容器中
          self.callbacks.push({
            onResolved(value) {
              handle(onResolved);
            },
            onRejected(reason) {
              handle(onRejected);
            }
          });
        }
      });

      if (self.status === PENDING) {
        //保存回调方法 到一个对象中
        self.callbacks.push({
          onResolved,
          onRejected
        })
      } else if (self.status === RESOLVED) {
        setTimeout(() => {
          resolve(self.data)
        });
      } else {
        setTimeout(() => {
          reject(self.data);
        });
      }

    }

    catch(onRejected) {
      Promise.prototype.then(undefined, onRejected);
    }

    //Promise函数对象方法
    static resolve(value) {
      //返回一个状态结果为 成功或失败的promise对象
      return new Promise((resolve, reject) => {
        if (value instanceof Promise) {
          value.then(resolve, reject);
        } else {
          resolve(value);
        }
      })
    }

    static reject(reason) {
      //返回一个状态结果为失败的promise对象
      return new Promise((resolve, reject) => {
        reject(reason);
      })
    }

    static all(promises) {
      //保存所有成功的value的数组
      const values = new Array(promises.length);
      //记录成功promise的数量
      let resloveCount = 0;
      return new Promise((reslove, reject) => {
        promises.forEach((p, index) => {
          p.then(
            value => {
              resloveCount++;
              values[index] = value;
              if (resloveCount === promises.length) {
                reslove(values);
              }
            },
            reason => {
              reject(reason);
            }
          )
        });
      });
    }

    static race(promises) {
      return new Promise((resove, reject) => {
        promises.forEach((p, index) => {
          p.then(
            value => {
              resove(value);
            },
            reason => {
              reject(reason);
            }
          )
        });
      });
    }
  }
  //向外暴露Promise的构造函数
  window.Promise = Promise;
}
)(window)

async与await

  • async 函数:函数的返回值是promise对象,promise对象的状态结果由async函数执行的返回值决定;
  
  • await 表达式:一般情况下await右侧的表达式为promise对象,也可以是其他的值;‘
    • 若表达式是promise对象,await返回的是promise成功的值;
    • 若表达式是其他值,直接将此值作为await的返回值;
  • 注意事项:
    • await必须写在async函数中,但async函数中可以没有await;
    • 如果await的promise失败了,就会抛出异常,需要通过try...catch来捕获处理;
  

异步执行的宏队列与微队列

  • 在JS中 存储 待执行回调函数的 队列 有两种特定的队列,分别为宏队列和微队列;
  • 宏队列:用来保存待执行的宏任务回调函数,例如定时器回调,DOM事件回调,ajax回调;
  • 微队列:用来保存待执行的微任务回调函数,例如Promise回调,MutationObserver回调;
  • JS执行时会区分 这两个队列;
    • JS引擎首先必须先执行完所有的初始化同步任务代码;
    • 每次准备取出第一个宏任务执行前,都要将所有微任务一个一个取出来执行
  
image.png

你可能感兴趣的:(前端入门11 -- JavaScript之Promise)