Promise详尽指南

文章目录

1、常见的内置错误

1.1、ReferenceError:引用的变量不存在

console.log(a);  // Uncaught ReferenceError: a is not defined

1.2、TypeError:数据类型不正确的错误

let a;
console.log(a.xxx); //Uncaught TypeError: Cannot read property 'xxx' of undefined

1.3、RangeError:数据值不在其所允许的范围内

function fn() {
  fn()
}
fn()  //Uncaught RangeError: Maximum call stack size exceeded

1.4、SyntaxError:语法错误

const c = """"; //Uncaught SyntaxError: Unexpected string

2、错误的处理(捕获与抛出)

2.1、捕获错误

通过try...catch可以捕获到JS中的错误信息,错误信息包含在catch的一个对象里面,捕获错误之后,JS代码可以继续往下执行,其中的错误对象包含两个属性:

message属性:错误相关信息

stack属性:函数调用栈记录信息

try {
    let d;
    console.log(d.xxx);
  } catch (error) {
    console.log(error.message); //Cannot read property 'xxx' of undefined
    console.log(error.stack); //TypeError: Cannot read property 'xxx' of undefined
  }
  console.log('出错之后可以继续往下执行');  //出错之后可以继续往下执行

2.2、抛出错误

通过throw new Error(),我们可以向外部抛出一个自定义的错误信息。

// 抛出错误:throw error
  function something() {
    if (Date.now() % 2 === 1) {
      console.log('当前时间为奇数,可以执行任务');
    } else {  //如果时间是偶数抛出异常,由调用来处理
      throw new Error('当前时间为偶数无法执行任务')
    }
  }

  // 捕获错误
  try {
    something() //当前时间为奇数,可以执行任务
  } catch (error) {
    console.log(error); //Error: 当前时间为偶数无法执行任务
  }

3、Promise的理解与使用

3.1、promise是什么?

3.1.1、抽象表述:

Promise 是 JS 中进行异步编程的新的解决方案

3.1.2、具体表述:

(1) 从语法上来说:promise是一个构造函数

(2) 从功能上来说:promise对象用来封装一个异步操作并可以获取其结果

3.2、Promise的状态和状态的改变

3.2.1、3 种状态:

(1) 待定(pending)

(2) 兑现(fulfilled,有时候也称为“解决”,resolved)

(3) 拒绝(rejected)

3.2.2、状态改变

待定(pending)是期约的最初始状态。在待定状态下,期约可以落定(settled)为代表成功的兑现(fulfilled)状态,或者代表失败的拒绝(rejected)状态。无论落定为哪种状态都是不可逆的。只要从待定转换为兑现或拒绝,期约的状态就不再改变。而且,也不能保证期约必然会脱离待定状态。因此,组 织合理的代码无论期约解决(resolve)还是拒绝(reject),甚至永远处于待定(pending)状态,都应该具有恰当的行为。重要的是,期约的状态是私有的,不能直接通过 JavaScript 检测到。这主要是为了避免根据读取到的期约状态,以同步方式处理期约对象。另外,期约的状态也不能被外部 JavaScript 代码修改。这与不能读取该状态的原因是一样的:期约故意将异步行为封装起来,从而隔离外部的同步代码。

3.2.3、总结

pending ——> resolved

pending ——> rejected

只有这两种情况,且一个promise对象只能改变一次,无论变为成功还是失败,都会有一个结果数据,成功的结果数据一般称为vlaue,失败的结果数据一般称为reason。

3.3、Promise的基本运行流程

在这里插入图片描述

3.4、promise的基本使用

// 1、创建一个新的promise对象
const p = new Promise((resolve, reject) => {  //执行器函数
  // 2、执行异步操作任务
  setTimeout(() => {
    const time = Date.now(); //如果当前时间是偶数代表成功,否则代表失败
    // 3、如果成功了,调用resolve(value)
    if (time % 2 === 0) {
      resolve('成功的数据,time=' + time);
    } else {
      // 4、如果失败了,调用reject(reason)
      reject('失败的数据,time=' + time);
    }
  }, 1000);
});

p.then(
  value => { //接收得到成功的value数据  onResolved
    console.log('成功的回调', value);
  },
  reason => { //接受得到失败的reason数据  onRejected
    console.log('失败的回调', reason);
  }
)

4、Promise的API

4.1、Promise构造函数:promise(excutor){}

excutor函数:同步执行,(resolve,reject)=>{}

resolve函数:内部定义成功时我们调用的函数 value =>{}

reject函数:内部定义失败时我们调用的函数reason =>{}

说明:excutor会在promise内部立即同步回调,异步操作在执行器中执行

4.2、Promise.prototype.then方法:(onResolved,onRejected)=>{}

onResolved函数:成功的回调函数 (value)=>{}

onRejected函数:失败的回调函数 (reason)=>{}

说明:指定用于得到成功value的成功回调和用于得到失败reason的失败回调,返回一个新的promise对象

4.3、Promise.prototype.catch方法:(onRejected)=>{}

onRejected函数:失败的回调函数 (reason)=>{}

说明:then()的语法糖,相当于hen(undefined,onRejected)

4.4、Promise.resolve方法:(value)=>{}

value:成功的数据或promise对象

说明:返回一个成功/失败的promise对象

4.5、Promise.reject方法:(reason)=>{}

reason:失败的原因

说明:返回一个失败的promise对象

4.6、Promise.all方法:(promises)=>{}

promises:包含n个promise的数组

说明:返回一个新的promise,只有所有的promise都成功才成功,只要有一个失败了就直接失败

4.7、Promise.race方法:mises)=>{}

promises:包含n个promise的数组

说明:返回一个新的promise,第一个完成的promise的结果状态就是最终的结果状态

4.8、Promise.any()

接收一个Promise可迭代对象,只要其中的一个 promise 成功,就返回那个已经成功的 promise 。

如果可迭代对象中没有一个 promise 成功(即所有的 promises 都失败/拒绝),就返回一个失败的 promise 和AggregateError类型的实例,

它是 Error 的一个子类,用于把单一的错误集合在一起。本质上,这个方法和Promise.all()是相反的。

4.9、Promise.allSettled()

​ 该Promise.allSettled()方法返回一个在所有给定的promise都已经fulfilledrejected后的promise,并带有一个对象数组,每个对象表示对应的promise结果。

​ 当您有多个彼此不依赖的异步任务成功完成时,或者您总是想知道每个promise的结果时,通常使用它。

相比之下,Promise.all()更适合彼此相互依赖或者在其中任何一个reject时立即结束。

代码展示:

new Promise((resolve, reject) => {
    setTimeout(() => {
      // resolve('成功的数据');
      reject('失败的数据');
    }, 1000);
  }).then(value => {
    console.log('onResolved1', value);
  }).catch(reason => {
    console.log('onRejected()1', reason);
  })

  //  产生一个成功值为1的promise对象
  const p1 = new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(1);
    }, 100);
  })
  const p2 = Promise.resolve(2);
  const p3 = Promise.reject(3);
  p1.then(value => { console.log(value) })  //1
  p2.then(value => { console.log(value) })  //2
  p3.then(null, reason => { console.log(reason) })  //3
  p3.catch(reason => { console.log(reason) }) //3

  // const pAll = Promise.all([p1, p2, p3]);
  const pAll = Promise.all([p1, p2]);
  pAll.then(
    values => {
      console.log('all onResolved()', values);
    },
    reason => {
      console.log('all onRejected()', reason);
    }
  );  //all onResolved() (2) [1, 2]

  // 第一个完成的promise的结果状态就是最终的结果状态
  const pRace = Promise.race([p1, p2, p3]);
  pRace.then(
    values => {
      console.log('race onResolved()', values);
    },
    reason => {
      console.log('race onRejected()', reason);
    }
  )   //race onResolved() 2

  const pAny = Promise.race([p1, p2, p3]);
  pAny.then(
    values => {
      console.log('any onResolved()', values);
    },
    reason => {
      console.log('any onRejected()', reason);
    }
  )   //any onResolved() 2

5、Promise的几个关键问题

5.1、如何改变promise的状态?

(1)resolve(value):如果当前是pendding就会变为resolved

(2)reject(reason):如果当前是pendding就会变为rejected

(3)抛出异常:如果当前是pendding就会变为rejected

const p = new Promise((resolve, reject) => {
  // resolve(1)  //promise变为resolved成功状态
  // reject(2) //promise变为rejected失败状态
  // throw new Error('出错了!');  //抛出异常,promise变为rejected失败状态,reason为抛出的error
  throw 3   //抛出异常,promise变为rejected失败状态,reason为抛出的3
});

p.then(
  value => { },
  reason => { console.log('reason', reason); }  //reason 3
)

5.2、一个promise指定多个成功/失败回调函数,都会调用吗?

当promise改变为对应状态时都会调用

const p = new Promise((resolve, reject) => {
  // resolve(1)  //promise变为resolved成功状态
  // reject(2) //promise变为rejected失败状态
  // throw new Error('出错了!');  //抛出异常,promise变为rejected失败状态,reason为抛出的error
  throw 3   //抛出异常,promise变为rejected失败状态,reason为抛出的3
});

p.then(
  value => { },
  reason => { console.log('reason', reason); }  //reason 3
)

p.then(
  value => { },
  reason => { console.log('reason2', reason); }  //reason2 3
)

5.3、改变promise状态和指定回调函数谁先谁后?

(1)都有可能,正常情况下是先指定回调函数再改变状态,但也可以先改变状态再指定回调

(2)如何先改变状态再指定回调?

1、在执行器中直接调用resolve()/reject()

2、延迟更长时间才才调用then()

(3)什么时候才能得到数据?

1、如果先指定的回调,那当状态发生改变时,回调函数就会调用,得到数据

2、如果先改变的状态,那当指定回调时,回调函数就会调用,得到数据

//常规:先指定回调函数,后改变状态
new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve(1); //后改变状态(同时指定数据),异步执行回调函数
  }, 1000);
}).then(  //先指定回调函数,保存当前指定的回调函数
  value => { console.log('value', value); },
  reason => { console.log('reason', reason); }
)

//如何先改变状态再指定回调?
new Promise((resolve, reject) => {
  resolve(1); //先改变状态(同时指定数据)
}).then(  //后指定回调函数,异步执行回调函数
  value => { console.log('value2', value); },
  reason => { console.log('reason2', reason); }
)

const p = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve(1); //先改变状态(同时指定数据)
  }, 1000);
});

setTimeout(() => {
  p.then(  //后指定回调函数,异步执行回调函数
    value => { console.log('value3', value); },
    reason => { console.log('reason3', reason); }
  )
}, 1100);

5.4、promise.then()返回的新的promise的结果状态由什么决定?

(1)简单表述:由then()指定的回调函数执行的结果决定

(2)详细表述:

1、如果抛出异常,新promise变为rejected,reason为抛出的异常

2、如果返回的是非promise的任意值,新promise变为resolved,value为返回的值

3、如果返回的是另一个新promise,此promise的结果就会成为新promise的结果

new Promise((resolve, reject) => {
  // resolve(1)  
  reject(2)
}).then(
  value => {
    console.log('onResolved1()', value);
    // return 2;
    // return {a:1}
    // return Promise.resolve(3)
    // return Promise.reject(4)
    throw 5;
  },
  reason => {
    console.log('onRejected1()', reason);
    // return 2;
    // return {a:1}
    // return Promise.resolve(3)
    // return Promise.reject(4)
    throw 5;
  }
).then(
  value => {
    console.log('onResolved2()', value);
  },
  reason => {
    console.log('onRejected2()', reason);
  }
)

5.5、promise如何串联多个操作任务?

(1)promise的then()返回一个新的promise,可以看成then()的链式调用

(2)通过then的链式调用串联多个同步/异步任务,异步任务必须放到promise中。

new Promise((resolve, reject) => {
  setTimeout(() => {
    console.log('执行任务1(异步)');
    resolve(1)
  }, 1000)
}).then(
  value => {
    console.log('任务1的结果', value);
    console.log('执行任务2(同步)');
    return 2;
  }
).then(
  value => {
    console.log('任务2的结果', value);
    return new Promise((resolve, reject) => {
      // 启动任务3(异步)
      setTimeout(() => {
        console.log('执行任务3(异步)');
        resolve(3)
      }, 1000)
    })
  }
).then(
  value => {
    console.log('任务3的结果', value);
  }
)

/*
  执行任务1(异步)
  任务1的结果 1
  执行任务2(同步)
  任务2的结果 2
  执行任务3(异步)
  任务3的结果 3
 */

5.6、promise异常传/穿透?

(1)当使用promise的then链式调用时,可以在最后指定失败的回调,

(2)前面任何操作出了异常,都会传到最后失败的回调中处理

new Promise((resolve, reject) => {
    // resolve(1);
    reject(1)
  }).then(
    value => {
      console.log('onResolved1()', value);
      return 2;
    },
    // 没写catch,就相当于写了下面这句
    // reason => { throw reason }
  ).then(
    value => {
      console.log('onResolved2()', value);
      return 3;
    },
    // 没写catch,就相当于写了下面这句
    reason => { throw reason }
  ).then(
    value => {
      console.log('onResolved3()', value);
    },
    // 没写catch,就相当于写了下面这句
    // reason => { throw reason }
    // 也可以是下面这句
    reason => Promise.reject(reason)
  ).catch(
    reason => {
      console.log('onRejected()', reason);
    }
  )

5.7、中断promise链?

(1)当使用promise的then链式调用时,在中间中断,不再调用后面的回调函数

(2)办法:在回调函数中返回一个pendding状态的promise对象

new Promise((resolve, reject) => {
    // resolve(1);
    reject(1)
  }).then(
    value => {
      console.log('onResolved1()', value);
      return 2;
    },
    // 没写catch,就相当于写了下面这句
    // reason => { throw reason }
  ).then(
    value => {
      console.log('onResolved2()', value);
      return 3;
    },
    // 没写catch,就相当于写了下面这句
    reason => { throw reason }
  ).then(
    value => {
      console.log('onResolved3()', value);
    },
    // 没写catch,就相当于写了下面这句
    // reason => { throw reason }
    // 也可以是下面这句
    reason => Promise.reject(reason)
  ).catch(
    reason => {
      console.log('onRejected()', reason);
      // 返回下面两句,进入失败的回调
      // throw reason;
      // return Promise.reject(reason)
      return new Promise(() => { }) //返回一个pendding的promise,中断promise链
    }
  ).then(
    value => {
      console.log('onResolved4()', value);
    },
    reason => {
      console.log('onRejected2()', reason);
    }
  )

6、自定义(手写)Promise

6.1、定义整体结构

新建文件lib/promise,存放我们自定义的Promise

/* 
自定义Promise函数模块:IIFE
*/
(function (window) {
  /* 
  Promise构造函数
  excutor: 执行器函数(同步执行)
  */
  function Promise() {}

  /* 
  Promise原型对象的then()
  指定成功和失败的回调函数
  返回一个新的promise对象
  */
  Promise.prototype.then = function (onResolved, onRejected) {}

  /* 
  Promise原型对象的catch()
  指定失败的回调函数
  返回一个新的promise对象
  */
  Promise.prototype.catch = function (onRejected) {}

  /* 
  Promise函数对象的resolve方法
  返回一个指定结果的成功的promise
  */
  Promise.resolve = function (value) {}

  /* 
  Promise函数对象的reject方法
  返回一个指定的reason的失败的promise
  */
  Promise.reject = function (reason) {}

  /* 
  Promise函数对象的all方法
  返回一个promise,只有当所有promise都成功时才成功,否则只要有一个失败就失败
  */
  Promise.all = function (promises) {}

  /* 
  Promise函数对象的race方法
  返回一个promise,其结果由第一个完成的promise决定
  */
  Promise.race = function (promises) {}

  // 向外暴露Promise函数
  window.Promise = Promise;
})(window)

6.2、实现Promise构造函数

先简单实现

/* 
  Promise构造函数
  excutor: 执行器函数(同步执行)
  */
  function Promise(excutor) {
    // 将当前promise对象保存起来
    const self = this;
    // 给promise对象指定status属性,初始值为pendding
    self.status = 'pending';
    // 给promise对象指定一个用于存储结果数据的属性
    self.data = undefined;
    // 每个元素的结构:{ onResolved(){}, onRejected(){} }
    self.callbacks = [];

    function resolve(value) {
      // 如果当前状态不是pending,直接结束
      if (self.status !== 'pending') {
        return
      }

      // 将状态改为resolved
      self.status = 'resolved';
      // 保存value数据
      self.data = value;
      // 如果有待执行callback函数,立即异步执行回调函数onResolved
      if (self.callbacks.length > 0) {
        setTimeout(() => { //放入队列中执行所有成功的回调
          self.callbacks.forEach(calbacksObj => {
            calbacksObj.onResolved(value)
          });
        });
      }
    }

    function reject(reason) {
      // 如果当前状态不是pending,直接结束
      if (self.status !== 'pending') {
        return
      }

      // 将状态改为rejected
      self.status = 'rejected';
      // 保存value数据
      self.data = reason;
      // 如果有待执行callback函数,立即异步执行回调函数onRejected
      if (self.callbacks.length > 0) {
        setTimeout(() => { //放入队列中执行所有成功的回调
          self.callbacks.forEach(calbacksObj => {
            calbacksObj.onRejected(reason)
          });
        });
      }
    }

    // 立即同步执行excutor
    try {
      excutor(resolve, reject)
    } catch (error) { //如果执行器抛出异常,promise对象变为rejected状态
      reject(error)
    }
  }

6.3、Promise.then方法的实现

/* 
  Promise原型对象的then()
  指定成功和失败的回调函数
  返回一个新的promise对象
  返回promise的结果由onResolved/onRejected执行结果决定
  */
  Promise.prototype.then = function (onResolved, onRejected) {
    // 向后传递成功的value
    onResolved = typeof onResolved === 'function' ? onResolved : value => value
    // 指定默认的失败的回调,(实现错误/异常穿透的关键点)
    onRejected = typeof onRejected === 'function' ? onRejected : reason => { //向后传递失败的reason
      throw reason
    }
    const self = this;

    // 返回一个新的promise
    return new Promise((resolve, reject) => {

      /* 
      调用指定的回调函数处理,根据执行结果,改变return的promise的状态
      */
      function handle(callback) {
        /* 
        1、如果抛出异常,return的promise就会失败,reason就是error
        2、如果回调函数返回不是promise,return的promise就会成功,value就是返回的值
        3、如果回调函数返回是promise,return的promise结果就是这个promise的结果
        */
        try {
          const result = callback(self.data);
          // 3、如果回调函数返回是promise,return的promise结果就是这个promise的结果
          if (result instanceof Promise) {
            // result.then(
            //   value => resolve(value), // 当result成功时,让return的promise也成功
            //   reason => reject(reason) // 当result失败时,让return的promise也失败
            // )
            // 简写
            result.then(resolve, reject)
          } else {
            // 2、如果回调函数返回不是promise,return的promise就会成功,value就是返回的值
            resolve(result)
          }
        } catch (error) {
          // 1、如果抛出异常,return的promise就会失败,reason就是error
          reject(error)
        }
      }

      if (self.status === PENDING) {
        // 当前状态还是pending状态,将回调函数保存起来
        self.callbacks.push({
          onResolved(value) {
            handle(onResolved)
          },
          onRejected(reason) {
            handle(onRejected)
          }
        })
      } else if (self.status === RESOLVED) { // 如果当前是resolved状态,异步执行onResolved并改变return的promise状态
        setTimeout(() => {
          handle(onResolved)
        });
      } else { // 如果当前是'rejected'状态,异步执行onRejected并改变return的promise状态
        setTimeout(() => {
          handle(onRejected)
        });
      }
    })

  }

6.4、Promise.catch方法的实现

/* 
  Promise原型对象的catch()
  指定失败的回调函数
  返回一个新的promise对象
  */
  Promise.prototype.catch = function (onRejected) {
    return this.then(undefined, onRejected)
  }

6.5、Promise.resolve()/reject()方法的实现

/* 
  Promise函数对象的resolve方法
  返回一个指定结果的成功的promise
  */
  Promise.resolve = function (value) {
    // 返回一个成功/失败的promise
    return new Promise((resolve, reject) => {
      // value 是promise
      if (value instanceof Promise) { // 使用value的结果作为promise的结果
        value.then(resolve, reject);
      } else { // value 不是promise => promise变为成功,数据是value
        resolve(value);
      }
    })
  }

  /* 
  Promise函数对象的reject方法
  返回一个指定的reason的失败的promise
  */
  Promise.reject = function (reason) {
    // 返回一个失败的promise
    return new Promise((resolve, reject) => {
      reject(reason)
    })
  }

6.6、Promise.all()方法的实现

/* 
  Promise函数对象的all方法
  返回一个promise,只有当所有promise都成功时才成功,否则只要有一个失败就失败
  */
  Promise.all = function (promises) {
    // 用来保存所有成功value的数组
    const values = new Array(promises.length);
    // 用来保存成功promise的数量
    let resolvedCount = 0;
    // 返回一个新的promise
    return new Promise((resolve, reject) => {
      // 遍历promises获取每个promise的结果
      promises.forEach((p, index) => {
        Promise.resolve(p).then(
          value => {
            resolvedCount++ //成功的数量加1
            // p成功,将成功的value保存到values
            values[index] = value
            // 如果全部成功了,将return的promise改变成功
            if (resolvedCount === promises.length) {
              resolve(values)
            }
          },
          reason => { // 只要一个失败了,return的promise就失败
            reject(reason)
          }
        )
      })
    })
  }

6.7、Promise.race()方法的实现

/* 
  Promise函数对象的race方法
  返回一个promise,其结果由第一个完成的promise决定
  */
  Promise.race = function (promises) {
    // 返回一个新的promise
    return new Promise((resolve, reject) => {
      // 遍历promises获取每个promise的结果
      promises.forEach((p, index) => {
        Promise.resolve(p).then(
          value => { // 一旦有成功了,将return变为成功
            resolve(value)
          },
          reason => { // 一旦有失败了,将return变为失败
            reject(reason)
          }
        )
      })
    })
  }

6.8、自定义Promise.resolveDelay()方法

/* 
  返回一个promise对象,它在指定的时间之后才确定结果
  */
  Promise.resolveDelay = function (value, time) {
    // 返回一个成功/失败的promise
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        // value 是promise
        if (value instanceof Promise) { // 使用value的结果作为promise的结果
          value.then(resolve, reject);
        } else { // value 不是promise => promise变为成功,数据是value
          resolve(value);
        }
      }, time);
    })
  }

6.9、自定义Promise.rejectDelay()方法

/* 
  返回一个promise对象,它在指定的时间之后才失败
  */
  Promise.rejectDelay = function (reason, time) {
    // 返回一个失败的promise
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        reject(reason)
      }, time);
    })
  }

6.10、手写Promise完整版

/* 
自定义Promise函数模块:IIFE
*/
(function (window) {

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

  /* 
  Promise构造函数
  excutor: 执行器函数(同步执行)
  */
  function Promise(excutor) {
    // 将当前promise对象保存起来
    const self = this;
    // 给promise对象指定status属性,初始值为pendding
    self.status = PENDING;
    // 给promise对象指定一个用于存储结果数据的属性
    self.data = undefined;
    // 每个元素的结构:{ onResolved(){}, onRejected(){} }
    self.callbacks = [];

    function resolve(value) {
      // 如果当前状态不是pending,直接结束
      if (self.status !== PENDING) {
        return
      }

      // 将状态改为resolved
      self.status = RESOLVED;
      // 保存value数据
      self.data = value;
      // 如果有待执行callback函数,立即异步执行回调函数onResolved
      if (self.callbacks.length > 0) {
        setTimeout(() => { //放入队列中执行所有成功的回调
          self.callbacks.forEach(calbacksObj => {
            calbacksObj.onResolved(value)
          });
        });
      }
    }

    function reject(reason) {
      // 如果当前状态不是pending,直接结束
      if (self.status !== PENDING) {
        return
      }

      // 将状态改为rejected
      self.status = REJECTED;
      // 保存value数据
      self.data = reason;
      // 如果有待执行callback函数,立即异步执行回调函数onRejected
      if (self.callbacks.length > 0) {
        setTimeout(() => { //放入队列中执行所有成功的回调
          self.callbacks.forEach(calbacksObj => {
            calbacksObj.onRejected(reason)
          });
        });
      }
    }

    // 立即同步执行excutor
    try {
      excutor(resolve, reject)
    } catch (error) { //如果执行器抛出异常,promise对象变为rejected状态
      reject(error)
    }
  }

  /* 
  Promise原型对象的then()
  指定成功和失败的回调函数
  返回一个新的promise对象
  返回promise的结果由onResolved/onRejected执行结果决定
  */
  Promise.prototype.then = function (onResolved, onRejected) {
    // 向后传递成功的value
    onResolved = typeof onResolved === 'function' ? onResolved : value => value
    // 指定默认的失败的回调,(实现错误/异常穿透的关键点)
    onRejected = typeof onRejected === 'function' ? onRejected : reason => { //向后传递失败的reason
      throw reason
    }
    const self = this;

    // 返回一个新的promise
    return new Promise((resolve, reject) => {

      /* 
      调用指定的回调函数处理,根据执行结果,改变return的promise的状态
      */
      function handle(callback) {
        /* 
        1、如果抛出异常,return的promise就会失败,reason就是error
        2、如果回调函数返回不是promise,return的promise就会成功,value就是返回的值
        3、如果回调函数返回是promise,return的promise结果就是这个promise的结果
        */
        try {
          const result = callback(self.data);
          // 3、如果回调函数返回是promise,return的promise结果就是这个promise的结果
          if (result instanceof Promise) {
            // result.then(
            //   value => resolve(value), // 当result成功时,让return的promise也成功
            //   reason => reject(reason) // 当result失败时,让return的promise也失败
            // )
            // 简写
            result.then(resolve, reject)
          } else {
            // 2、如果回调函数返回不是promise,return的promise就会成功,value就是返回的值
            resolve(result)
          }
        } catch (error) {
          // 1、如果抛出异常,return的promise就会失败,reason就是error
          reject(error)
        }
      }

      if (self.status === PENDING) {
        // 当前状态还是pending状态,将回调函数保存起来
        self.callbacks.push({
          onResolved(value) {
            handle(onResolved)
          },
          onRejected(reason) {
            handle(onRejected)
          }
        })
      } else if (self.status === RESOLVED) { // 如果当前是resolved状态,异步执行onResolved并改变return的promise状态
        setTimeout(() => {
          handle(onResolved)
        });
      } else { // 如果当前是'rejected'状态,异步执行onRejected并改变return的promise状态
        setTimeout(() => {
          handle(onRejected)
        });
      }
    })

  }

  /* 
  Promise原型对象的catch()
  指定失败的回调函数
  返回一个新的promise对象
  */
  Promise.prototype.catch = function (onRejected) {
    return this.then(undefined, onRejected)
  }

  /* 
  Promise函数对象的resolve方法
  返回一个指定结果的成功的promise
  */
  Promise.resolve = function (value) {
    // 返回一个成功/失败的promise
    return new Promise((resolve, reject) => {
      // value 是promise
      if (value instanceof Promise) { // 使用value的结果作为promise的结果
        value.then(resolve, reject);
      } else { // value 不是promise => promise变为成功,数据是value
        resolve(value);
      }
    })
  }

  /* 
  Promise函数对象的reject方法
  返回一个指定的reason的失败的promise
  */
  Promise.reject = function (reason) {
    // 返回一个失败的promise
    return new Promise((resolve, reject) => {
      reject(reason)
    })
  }

  /* 
  Promise函数对象的all方法
  返回一个promise,只有当所有promise都成功时才成功,否则只要有一个失败就失败
  */
  Promise.all = function (promises) {
    // 用来保存所有成功value的数组
    const values = new Array(promises.length);
    // 用来保存成功promise的数量
    let resolvedCount = 0;
    // 返回一个新的promise
    return new Promise((resolve, reject) => {
      // 遍历promises获取每个promise的结果
      promises.forEach((p, index) => {
        Promise.resolve(p).then(
          value => {
            resolvedCount++ //成功的数量加1
            // p成功,将成功的value保存到values
            values[index] = value
            // 如果全部成功了,将return的promise改变成功
            if (resolvedCount === promises.length) {
              resolve(values)
            }
          },
          reason => { // 只要一个失败了,return的promise就失败
            reject(reason)
          }
        )
      })
    })
  }

  /* 
  Promise函数对象的race方法
  返回一个promise,其结果由第一个完成的promise决定
  */
  Promise.race = function (promises) {
    // 返回一个新的promise
    return new Promise((resolve, reject) => {
      // 遍历promises获取每个promise的结果
      promises.forEach((p, index) => {
        Promise.resolve(p).then(
          value => { // 一旦有成功了,将return变为成功
            resolve(value)
          },
          reason => { // 一旦有失败了,将return变为失败
            reject(reason)
          }
        )
      })
    })
  }

  /* 
  返回一个promise对象,它在指定的时间之后才确定结果
  */
  Promise.resolveDelay = function (value, time) {
    // 返回一个成功/失败的promise
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        // value 是promise
        if (value instanceof Promise) { // 使用value的结果作为promise的结果
          value.then(resolve, reject);
        } else { // value 不是promise => promise变为成功,数据是value
          resolve(value);
        }
      }, time);
    })
  }

  /* 
  返回一个promise对象,它在指定的时间之后才失败
  */
  Promise.rejectDelay = function (reason, time) {
    // 返回一个失败的promise
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        reject(reason)
      }, time);
    })
  }
  
  // 向外暴露Promise函数
  window.Promise = Promise;
})(window)

7、自定义(手写)Promise之class版

/* 
自定义Promise函数模块:IIFE
*/
(function (window) {

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

  class Promise {
    /* 
  Promise构造函数
  excutor: 执行器函数(同步执行)
  */
    constructor(excutor) {
      // 将当前promise对象保存起来
      const self = this;
      // 给promise对象指定status属性,初始值为pendding
      self.status = PENDING;
      // 给promise对象指定一个用于存储结果数据的属性
      self.data = undefined;
      // 每个元素的结构:{ onResolved(){}, onRejected(){} }
      self.callbacks = [];

      function resolve(value) {
        // 如果当前状态不是pending,直接结束
        if (self.status !== PENDING) {
          return
        }

        // 将状态改为resolved
        self.status = RESOLVED;
        // 保存value数据
        self.data = value;
        // 如果有待执行callback函数,立即异步执行回调函数onResolved
        if (self.callbacks.length > 0) {
          setTimeout(() => { //放入队列中执行所有成功的回调
            self.callbacks.forEach(calbacksObj => {
              calbacksObj.onResolved(value)
            });
          });
        }
      }

      function reject(reason) {
        // 如果当前状态不是pending,直接结束
        if (self.status !== PENDING) {
          return
        }

        // 将状态改为rejected
        self.status = REJECTED;
        // 保存value数据
        self.data = reason;
        // 如果有待执行callback函数,立即异步执行回调函数onRejected
        if (self.callbacks.length > 0) {
          setTimeout(() => { //放入队列中执行所有成功的回调
            self.callbacks.forEach(calbacksObj => {
              calbacksObj.onRejected(reason)
            });
          });
        }
      }

      // 立即同步执行excutor
      try {
        excutor(resolve, reject)
      } catch (error) { //如果执行器抛出异常,promise对象变为rejected状态
        reject(error)
      }
    }

    /* 
  Promise原型对象的then()
  指定成功和失败的回调函数
  返回一个新的promise对象
  返回promise的结果由onResolved/onRejected执行结果决定
  */
    then(onResolved, onRejected) {
      // 向后传递成功的value
      onResolved = typeof onResolved === 'function' ? onResolved : value => value
      // 指定默认的失败的回调,(实现错误/异常穿透的关键点)
      onRejected = typeof onRejected === 'function' ? onRejected : reason => { //向后传递失败的reason
        throw reason
      }
      const self = this;

      // 返回一个新的promise
      return new Promise((resolve, reject) => {

        /* 
        调用指定的回调函数处理,根据执行结果,改变return的promise的状态
        */
        function handle(callback) {
          /* 
          1、如果抛出异常,return的promise就会失败,reason就是error
          2、如果回调函数返回不是promise,return的promise就会成功,value就是返回的值
          3、如果回调函数返回是promise,return的promise结果就是这个promise的结果
          */
          try {
            const result = callback(self.data);
            // 3、如果回调函数返回是promise,return的promise结果就是这个promise的结果
            if (result instanceof Promise) {
              // result.then(
              //   value => resolve(value), // 当result成功时,让return的promise也成功
              //   reason => reject(reason) // 当result失败时,让return的promise也失败
              // )
              // 简写
              result.then(resolve, reject)
            } else {
              // 2、如果回调函数返回不是promise,return的promise就会成功,value就是返回的值
              resolve(result)
            }
          } catch (error) {
            // 1、如果抛出异常,return的promise就会失败,reason就是error
            reject(error)
          }
        }

        if (self.status === PENDING) {
          // 当前状态还是pending状态,将回调函数保存起来
          self.callbacks.push({
            onResolved(value) {
              handle(onResolved)
            },
            onRejected(reason) {
              handle(onRejected)
            }
          })
        } else if (self.status === RESOLVED) { // 如果当前是resolved状态,异步执行onResolved并改变return的promise状态
          setTimeout(() => {
            handle(onResolved)
          });
        } else { // 如果当前是'rejected'状态,异步执行onRejected并改变return的promise状态
          setTimeout(() => {
            handle(onRejected)
          });
        }
      })

    }

    /* 
    Promise原型对象的catch()
    指定失败的回调函数
    返回一个新的promise对象
    */
    catch (onRejected) {
      return this.then(undefined, onRejected)
    }

    /* 
    Promise函数对象的resolve方法
    返回一个指定结果的成功的promise
    */
    static resolve = function (value) {
      // 返回一个成功/失败的promise
      return new Promise((resolve, reject) => {
        // value 是promise
        if (value instanceof Promise) { // 使用value的结果作为promise的结果
          value.then(resolve, reject);
        } else { // value 不是promise => promise变为成功,数据是value
          resolve(value);
        }
      })
    }

    /* 
    Promise函数对象的reject方法
    返回一个指定的reason的失败的promise
    */
    static reject = function (reason) {
      // 返回一个失败的promise
      return new Promise((resolve, reject) => {
        reject(reason)
      })
    }

    /* 
    Promise函数对象的all方法
    返回一个promise,只有当所有promise都成功时才成功,否则只要有一个失败就失败
    */
    static all = function (promises) {
      // 用来保存所有成功value的数组
      const values = new Array(promises.length);
      // 用来保存成功promise的数量
      let resolvedCount = 0;
      // 返回一个新的promise
      return new Promise((resolve, reject) => {
        // 遍历promises获取每个promise的结果
        promises.forEach((p, index) => {
          Promise.resolve(p).then(
            value => {
              resolvedCount++ //成功的数量加1
              // p成功,将成功的value保存到values
              values[index] = value
              // 如果全部成功了,将return的promise改变成功
              if (resolvedCount === promises.length) {
                resolve(values)
              }
            },
            reason => { // 只要一个失败了,return的promise就失败
              reject(reason)
            }
          )
        })
      })
    }

    /* 
    Promise函数对象的race方法
    返回一个promise,其结果由第一个完成的promise决定
    */
    static race = function (promises) {
      // 返回一个新的promise
      return new Promise((resolve, reject) => {
        // 遍历promises获取每个promise的结果
        promises.forEach((p, index) => {
          Promise.resolve(p).then(
            value => { // 一旦有成功了,将return变为成功
              resolve(value)
            },
            reason => { // 一旦有失败了,将return变为失败
              reject(reason)
            }
          )
        })
      })
    }

    /* 
    返回一个promise对象,它在指定的时间之后才确定结果
    */
    static resolveDelay = function (value, time) {
      // 返回一个成功/失败的promise
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          // value 是promise
          if (value instanceof Promise) { // 使用value的结果作为promise的结果
            value.then(resolve, reject);
          } else { // value 不是promise => promise变为成功,数据是value
            resolve(value);
          }
        }, time);
      })
    }

    /* 
    返回一个promise对象,它在指定的时间之后才失败
    */
    static rejectDelay = function (reason, time) {
      // 返回一个失败的promise
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          reject(reason)
        }, time);
      })
    }
  }

  // 向外暴露Promise函数
  window.Promise = Promise;
})(window)

8、async函数

函数的返回值为promise对象

promise对象的结果由async函数执行的返回值决定

参考文档:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Statements/async_function

// async函数的返回值是一个promise对象
  // async函数返回的promise的结果由函数执行的结果决定
  async function fn1() {
    // return 1
    // throw 2
    // return Promise.reject(3);
    // return Promise.resolve(4);
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve(5)
      }, 1000);
    })
  }
  const result = fn1()
  // console.log(result);
  result.then(
    value => {
      console.log('onResolved()', value);
    },
    reason => {
      console.log('onRejected()', reason);
    }
  )

9、await

1、await 表达式

await右侧的表达式一般为promise对象,但也可以是其他的值

如果是promise对象,await返回的是promise成功的值

如果表达式是其他值,直接将此值作为await的返回值

2、注意:

await必须写在async函数中,但async函数中可以没有await

如果await的promise失败了,就会抛出异常,需要通过try…catch来捕获处理

3、参考文档:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/await

function fn2() {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        // resolve(6)
        reject(6)
      }, 1000);
    })
  }

  function fn4() {
    return 7
  }

  async function fn3() {
    try {
      const value = await fn2(); // await右侧表达式为promise,得到的结果就是promise对象的处理结果
    } catch (error) {
      console.log('得到失败的结果', error);
    }

    // const value = await fn4() // await右侧表达式不是promise,得到的结果就是它本身
    // console.log('value', value);
  }
  fn3()

10、JS异步之宏队列与微队列

JS 中用来存储待执行回调函数的队列包含 2 个不同特定的列队

宏列队: 用来保存待执行的宏任务(回调), 比如: 定时器回调/DOM 事件回调 /ajax 回调

微 列 队 : 用 来 保 存 待 执 行 的 微 任 务 ( 回 调 ), 比 如 : promise 的 回 调 /MutationObserver 的回调

JS 执行时会区别这 2 个队列

(1) JS 引擎首先必须先执行所有的初始化同步任务代码

(2) 每次准备取出第一个宏任务执行前, 都要将所有的微任务一个一个取出来执行

https://s3.ax1x.com/2020/12/03/DoOOtP.png

setTimeout(() => {  // 会立即放入宏队列
    console.log('timeout callback1()');
  }, 0);
  
  setTimeout(() => {  // 会立即放入宏队列
    console.log('timeout callback2()');
  }, 0);

  Promise.resolve(1).then(
    value => {  // 会立即放入微队列
      console.log('Promise onResolved1()', value);
    }
  )
  Promise.resolve(2).then(
    value => {  // 会立即放入微队列
      console.log('Promise onResolved2()', value);
    }
  )

11、相关面试题

setTimeout(() => {
    console.log(1);
  }, 0);

  Promise.resolve().then(() => {
    console.log(2);
  })

  Promise.resolve().then(() => {
    console.log(4);
  })

  console.log(3);

  // 3、2、4、1
setTimeout(() => {
    console.log(1);
  }, 0);

  new Promise((resolve) => {
    console.log(2);
    resolve()
  }).then(
    () => { console.log(3) }
  ).then(
    () => { console.log(4) }
  )
  console.log(5);

  // 2、5、3、4、1
const first = () => (new Promise((resolve, reject) => {
    console.log(3)
    let p = new Promise((resolve, reject) => {
      console.log(7)
      setTimeout(() => {
        console.log(5)
        resolve(6)
      }, 0)
      resolve(1)
    })
    resolve(2)
    p.then((arg) => {
      console.log(arg)
    })
  }))
  first().then((arg) => {
    console.log(arg)
  })
  console.log(4)

  // 3、7、4、1、2、5
setTimeout(() => {
    console.log("0")
  }, 0)
  new Promise((resolve, reject) => {
    console.log("1")
    resolve()
  }).then(() => {
    console.log("2")
    new Promise((resolve, reject) => {
      console.log("3")
      resolve()
    }).then(() => {
      console.log("4")
    }).then(() => {
      console.log("5")
    })
  }).then(() => {
    console.log("6")
  })
  new Promise((resolve, reject) => {
    console.log("7")
    resolve()
  }).then(() => {
    console.log("8")
  })

  // 1、7、2、3、8、4、6、5、0

文章最后:更多精彩文章和资源,欢迎参观我的公众号:小笑残虹。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值