Skip to content

Promise的认知细节 ​

一、executor函数 ​

  • Promise新建后executor函数就会立即执行: new Promise( (c, e) => { 立即执行})

二、正常处理 ​

  • resolve函数用于将Promise状态从pending转变为fulfilled,并将结果值传递给then回调函数。

    ts
    const promise = new Promise((resolve, reject) => {
      resolve(result);
    });
    
    promise.then(result => {
      console.log(result);
    });
  • resolve(promise):resolve(v)中的v可以是Promise实例。

    ts
      const thenable = new Promise((resolve, reject) => {
          resolve(result);
          // or
          reject(new Error('error'));
      });
      const promise = new Promise((resolve) => {
         resolve(thenable);
      });
      promise.then(result => {
        console.log(result);
      });
      promise.catch(error => {
        console.log(error);
      });

    此时promise的状态由thenable决定,promise自身怎么用resolve,reject都无效了,相当于thenable控制promise的状态:

    • 当thenable状态从pending转resolved,那么执行promise.then;
    • 当thenable状态从pending转rejected,那么执行promise.catch
  • Promise.resolve(promise):由于Promise.resolve(v)等价于new Promise(resolve => resolve(v)),所以Promise.resolve(promise)等价于new Promise(resolve => resolve(promise))。又因为当resolve(v)中的v是Promise实例时,则当前resolve所在的Promise实例的具体状态就由v决定。因此Promise.resolve(promise)的最终状态就由promise决定,Promise.resolve本身在这里只是起到了包装一个参数为Promise实例的作用,并不会影响promise的状态,别被它的名字中带resolve误导了,它不是将当前promise的状态转为resolved。简而言之,resolve(promise)拿到的是promise本身,接下来的行为都由它的状态来决定。

    实际工程上通常喜欢使用Promise.resolve(thenable)来包装一个thenable对象,从而确保thenable的then回调送入到微任务队列中执行,而不是立即同步执行。因为一个thenable对象的then方法可能是一个异步操作,也可能是一个同步操作,如果是一个同步操作,那么thenable的then回调会立即执行,此时我们为了统一行为,避免潜在的同步执行导致的问题,通常使用Promise.resolve(thenable)来统一将then回调送入微任务队列等到事件循环的末尾再执行。

三、异常处理 ​

  • reject函数用于将Promise状态从pending转变为rejected,并将错误信息传递给catch回调函数。

    ts
    const promise = new Promise((resolve, reject) => {
      reject(new Error('error'));
    });
    
    promise.catch(error => {
      console.log(error);
    });

    其中reject(e)中的e是Error实例,会被catch回调函数接收。

  • 在new Promise((c,e) => {…})当中执行抛出错误会令promise状态从pending转rejected,导致走catch回调。常见的抛出错误的方式如下:

    ts
    let promise: Promise<void>;
    
    // 方式一:直接抛出错误
    promise = new Promise(() => {
      throw new Error('error');
    });
    
    // 方式二:使用try...catch捕获错误
    promise = new Promise((_, reject) => {
      try{ 
          throw new Error('error'); 
      } catch(e) { 
          reject(e); 
      }
    });
    
    // 方式三:使用reject函数
    promise = new Promise((_, reject) => {
      reject(new Error('error'));
    });
    
    promise.catch(error => {
      console.log(error);
    });

    以上三种方式都会导致promise状态从pending转rejected,从而走catch回调。