Promise的关键问题

328 阅读4分钟

这是我参与8月更文挑战的第3天,活动详情查看:8月更文挑战

前面写了Promise的入门和相关方法的使用,其中讲了Promise的作用、状态、基本使用、执行顺序、相关方法的使用,需要的童鞋请移步。

这篇文章写下Promise需要注意的问题:

  1. 如何改变Promise的状态?
  2. 一个Promise指定多个成功/失败回调都会被调用吗?
  3. 改变Promise状态和指定回调函数谁先谁后?
  4. then()返回的新promise的结果状态由什么决定?
  5. Promise如何串连多个操作任务?
  6. 如何中断Promise链?

一、如何改变Promise的状态

  1. resolve(value): 如果当前是pending状态则变为fulfilled状态;
  2. reject(reason): 如果当前是pending状态则变为rejected状态;
  3. 抛出异常:如果当前是pending状态则变为rejected状态。
const p = new Promise(() => {
     // resolve(1); // Promise变为fulfilled状态
     // reject(2); // Promise变为rejected状态
    throw new Error("出错了"); // Promise变为rejected状态
});

二、一个Promise指定多个成功/失败回调都会被调用吗

一个Promise指定多个成功/失败回调都会被调用。

const p = new Promise(resolve => {
    resolve(1);
});
p.then(value => {
    console.log("第1个:" + value);
});
p.then(value => {
    console.log("第2个:" + value);
});

执行结果:

// 第1个回调函数被调用:1

// 第2个回调函数被调用:1

从例子中可以看出,p的两个then方法中的回调函数都被调用了,获取到的返回值都为1,。

三、改变Promise状态和指定回调函数谁先谁后

改变Promise状态和指定回调函数谁先谁后?

  1. 都有可能,正常状态下是 先指定回调函数 再改变状态,但也可以先改变状态再指定回调函数。
  2. 如何先改变状态再指定回调函数?
  • 在执行器中直接调用resolve()/reject()
  • 延迟调用then方法

方法一例子:

const p = new Promise(resolve => {
    resolve(1);
}).then(value => {
    console.log(value);
});

该例子中执行器中用同步的方式resolve(1),所以先改变了状态,再用then方法指定了回调函数。

方法二例子:

const p = new Promise(resolve => {
    resolve(1);
});
setTimeout(() => {
    p.then(value => {
        console.log(value);
    });
}, 100);

该例子中执行器中用同步的方式resolve(1),所以先改变了状态,再使用setTimeout方法来延迟then方法指定回调函数。

  1. 什么时候才能得到数据?
  • 如果先指定回调,那当状态发生改变时,回调函数就会调用,得到数据。
  • 如果先改变状态,那当指定回调是,回调函数调用,得到数据。

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

由then指定的回调函数执行的结果决定:

  • 若抛出异常,则新promise状态变为rejected,reason为抛出的异常。
  • 若返回的是非promise的任意值,则新promise状态变为fulfilled,value为返回的值。
  • 若返回的是另一个新的promise,则此promise的结果就会成为新promise的结果。 例子:
const p = new Promise(resolve => {
    reject(1);
}).then(
  val => {
    console.log("resolve1:", val);
  },
  reason => {
    console.log("reject1:", reason);
    // 无返回值,下一个then接收到的就是undefined
  }
).then(
  val => {
    console.log("resolve2:", val);
  },
  reason => {
    console.log("reject2:", reason);
  }
);

执行结果:

// reject1: 1

// resolve2: undefined

p中reject(1),使得第一个then方法接收到异常,执行了第二个参数中的回调函数。

第一个then执行完后没有异常,返回一个新的返回值为undefined的Promise,所以第二个then方法调用第一个参数的回调函数。

五、Promise如何串连多个操作任务

通过then的链式调用串连多个同步/异步任务。 例子:

const p = new Promise((resolve, reject) => {
  setTimeout(() => {
    console.log("异步任务1");
    resolve(1);
  });
})
  .then(val => {
    console.log("异步任务1的结果:", val);
    return 2;
  })
  .then(val => {
    // 下个then会等待这个promise执行完再执行
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        console.log("同步任务2的结果:", val);
        resolve(3);
      }, 100);
    });
  })
  .then(val => {
    console.log("异步任务3的结果:", val);
  });

执行结果:

// 异步任务1

// 异步任务1的结果: 1

// 同步任务2的结果: 2

// 异步任务3的结果: 3

第一个then方法中会等待前面Promise执行完后再执行。 then方法的回调函数中无法使用resolve来返回值,所以使用return来返回。 第二个then方法中返回一个新的Promise实例,第三个then会等到此Promise实例完成后再执行。

六、如何中断Promise链

采用链式写法,then方法后面会再调用另一个then方法,如果没有中断,将会一直调用,直到所有then方法都完成。那如何中断这条Promise链呢? 在回调函数中返回一个pending状态的promise对象即可中断promise链。

例子:

const p = new Promise((resolve, reject) => {
  resolve(1);
})
.then(val => {
  console.log(val);
  // 返回一个pending状态的promise对象,后面的then方法将不会执行
  return new Promise(() => {});
})
.then(val => {
  console.log("不会执行了:", val);
});

执行结果: // 1

第一个then方法中返回了一个pending状态的promise对象,一直没有返回结果, 第二个then方法一直等不到返回结果,所以并不会被执行,所以起到了中断Promise的效果。