前期准备

回调函数

同步回调函数
理解:立即执行,完全执行完之后才结束,不会方式回调队列中
列子:数组遍历forEach相关的回调函数

  1. const arr = [1, 3, 5]
  2. arr.forEach(item => { // 遍历回调,同步回调函数
  3. console.log(item)
  4. })
  5. console.log('forEach()之后')

image.png

异步回调函数
理解:不会立即执行,放入任务队列,等待同步任务执行栈之后完成后调用任务队列中的回调函数才执行
列子:定时器回调、AJAX回调、promise的回调

Promise 是什么

表达:Promise是JS中进行异步变成的新解决方案
具体表达:从语法上,promise是一个构造函数;从功能上,promise对象用来封装一个异步操作并可以获取其结果。

一个Promise的三种状态

在开始使用Promise之前,我们首先需要了解Promise的三种状态:

  • pending: 初始状态,既不是成功,也不是失败状态。
  • fulfilled: 意味着操作成功完成。
  • rejected: 意味着操作失败。

pending 状态的 Promise 对象可能会变为fulfilled 状态并传递一个值给相应的状态处理方法,也可能变为失败状态(rejected)并传递失败信息。当其中任一种情况出现时,Promise 对象的 then 方法绑定的处理方法(handlers )就会被调用(then方法包含两个参数:onfulfilled 和 onrejected,它们都是 Function 类型。当Promise状态为fulfilled时,调用 then 的 onfulfilled 方法,当Promise状态为rejected时,调用 then 的 onrejected 方法, 所以在异步操作的完成和绑定处理方法之间不存在竞争)。
因为Promise.prototype.thenPromise.prototype.catch方法返回promise 对象, 所以它们可以被链式调用
Promise - 图2
Promise的这三种状态有两个特点:

  • 对象的状态不受外界影响
    只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。这也是Promise这个名字的由来,它的英语意思就是“承诺”,表示其他手段无法改变。
  • 一旦状态改变,就不会再变,任何时候都可以得到这个结果
    Promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,这时就称为 resolved(已定型)。如果改变已经发生了,你再对Promise对象添加回调函数,也会立即得到这个结果。这与事件(Event)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的。

Promise 基本用法

  1. const p = new Promise((resolve, reject) => { // executor 执行器函数
  2. // 执行异步操作代码
  3. if(...) {
  4. resolve(value); // 成功
  5. } else {
  6. reject(error); // 失败
  7. }

Promise构造函数接收一个函数作为参数,该函数的两个参数分别是resolvereject。他们是两个函数,由JavaScript引擎提供,不用自己部署。
executor 执行器函数是带有 resolvereject 两个参数的函数 。Promise构造函数执行时立即调用executor 函数。
resolve函数的作用:当promise对象的状态从pending变为resovled,在异步操作成功时调用,将异步操作结果作为参数传递出去。
reject函数的作用:当promise对象的状态从pending变为rejected,在异步操作失败时调用,将异步操作错误信息作为参数传递出去。
promise实例对象生成后,可以用then方法分别执行resolved状态和rejected状态的回调函数。then方法可以接受两个回调函数作为参数。第一个回调函数是Promise对象的状态变为resolved时调用,第二个回调函数是Promise对象的状态变为rejected时调用。其中,第二个函数是可选的,不一定要提供。这两个函数都接受Promise对象传出的值作为参数。

  1. p.then((value) => { // onResolved
  2. // success
  3. }, (error) => { // onRejected
  4. // failure
  5. });

promise新建后会立即执行构造器函数部分

  1. let promise = new Promise((resolve, reject) => {
  2. console.log('11'); // 会立即执行,同步回调函数,宏任务
  3. resolve();
  4. });
  5. promise.then(() => {
  6. console.log('22'); // 微任务
  7. });
  8. console.log('33');
  9. // => 11
  10. // => 33
  11. // => 22

注意:调用resolvereject并不会终结 Promise的参数函数的执行。

  1. new Promise((resolve, reject) => {
  2. resolve(1); // 不影响
  3. console.log(2);
  4. }).then(r => {
  5. console.log(r);
  6. });
  7. // 2
  8. // 1

promise.then返回的新promise的结果状态有什么决定?

  • then指定的回调函数执行的结果决定
  • 如果抛出异常,新promise变为rejectedreason为抛出的异常
  • 如果返回的是非promise的任意值,新promise变为resolvedvalue为返回的值
  • 如果返回的是另一个新promise对象,此promise的结果就会成为下一个then函数中新promise的结果
    1. new Promise((resolve, reject) => {
    2. resolve(1); // 不影响
    3. console.log(2);
    4. }).then(value => {
    5. console.log('1', value);
    6. return '111';
    7. return Promise.resolve(3)
    8. }).then(value => {
    9. console.log('2',value);
    10. // '111' // 获取到上一个then函数里面resolv回调函数中的 return 字符串 '111'
    11. // 3 // 获取到上一个then函数里面resolv回调函数中的 return 的promise对象,成功值为3
    12. })

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

  1. promisethen()方法返回一个信息的promise,可以使用then()的链式调用
  2. 通过then的链式调用可以串联多个同步或者异步任务(异步任务需要返回promise对象)

    1. new Promise((resolve, reject) => {
    2. setTimeout(()=>{
    3. console.log('执行任务1(异步)')
    4. resolve(1)
    5. }, 1000)
    6. }).then(value =>{
    7. console.log('任务1的结果 =>' value)
    8. console.log('执行任务2(同步)')
    9. return 2
    10. }).then(value => {
    11. console.log('任务2的结果 =>' value)
    12. return new Promise((resolve, reject)=>{
    13. // 启动任务3(异步)
    14. setTimeout(()=>{
    15. console.log('执行任务3(异步)')
    16. resolve(3)
    17. }, 1000)
    18. })
    19. }).then(value =>{
    20. console.log('任务3的结果 =>' value)
    21. })
    22. // 执行任务1(同步)
    23. // 任务1结果:1
    24. // 执行任务2(同步)
    25. // 任务2结果:2
    26. // 执行任务3(异步)
    27. // 任务3结果:3

    结果:
    image.png

    promise异常穿透

  3. 当使用promisethen链式调用时,可以在最后指定失败的回调

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

中断promise链

  1. 当使用promisethen链式调用时,在中间中断,不再调用后面的回调函数
  2. 方法:在回调函数中返回一个pending状态的promise对象
    1. new Promise((resolve, reject) => {
    2. setTimeout(()=>{
    3. console.log('执行任务1(异步)')
    4. resolve(1)
    5. }, 1000)
    6. }).then(value =>{
    7. console.log('任务1的结果 =>' value)
    8. console.log('执行任务2(同步)')
    9. return 2
    10. }).catch(reason => {
    11. console.log('任务2的结果 =>' reason)
    12. return new Promise(() => {})
    13. // 返回一个状态为 pending的promise对象,中断 promise 链
    14. // 后面的 then 方法也不会执行
    15. }).then(value =>{
    16. console.log('任务3的结果 =>' value)
    17. })