准备

区别实例对象与函数对象

  1. 实例对象: new 函数产生的对象, 称为实例对象, 简称为对象

  2. 函数对象: 将函数作为对象使用时, 简称为函数对象

    1
    2
    3
    4
    5
    6
    function Fn() {} // Fn函数
    const fn = new Fn(); // Fn是构造函数 fn是实例对象(简称为对象)
    console.log(Fn.prototype); // Fn.属性 Fn是函数对象
    Fn.bind({}); // Fn.方法 Fn是函数对象
    $("#test"); // $是jquery函数
    $.get("/test"); // $是jquery函数对象

回调函数

  • 定义:按照调用者有的约定实现函数的功能,调用者不调用但会执行

  • 同步回调: 立即执行, 完全执行完了才结束, 不会放入回调队列中

    • 例子: 数组遍历相关的回调函数
    • Promise 的 excutor 函数
  • 异步回调: 不会立即执行, 会放入回调队列中将来执行

    • 定时器回调
    • ajax 回调
    • Promise 的成功|失败的回调
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    <script type="text/javascript">
    const arr = [1, 2, 3];
    // 立即执行, 完全执行完了才结束, 不会放入回调队列中
    arr.forEach((element) => {
    console.log(element);
    });
    console.log("forEach之后");

    // 不会立即执行, 会放入回调队列中将来执行
    setTimeout(() => {
    console.log("回调函数");
    }, 0);

    console.log("setTimeout之后");
    </script>

错误处理

  • 参考链接

  • 错误的类型

    • Error: 所有错误的父类型

    • ReferenceError: 引用的变量不存在

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

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

    • SyntaxError: 语法错误

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      // ReferenceError: 引用的变量不存在
      console.log(a) // ReferenceError: a is not defined
      console.log('-----') // 没有捕获error, 下面的代码不会执行

      // TypeError: 数据类型不正确的错误
      let b
      console.log(b.xxx) // TypeError: Cannot read property 'xxx' of undefined
      b = {}
      b.xxx() // TypeError: b.xxx is not a function

      // RangeError: 数据值不在其所允许的范围内
      function fn() {
      fn()
      }
      fn() // RangeError: Maximum call stack size exceeded

      // SyntaxError: 语法错误
      const c = """" // SyntaxError: Unexpected string
  • 错误处理

    • 捕获错误: try … catch

      1
      2
      3
      4
      5
      6
      7
      8
      try {
      let d;
      console.log(d.xxx);
      } catch (error) {
      console.log(error.message);
      console.log(error.stack);
      }
      console.log("出错之后");
    • 抛出错误: throw error

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      function something() {
      if (Date.now() % 2 === 1) {
      console.log("当前时间为奇数, 可以执行任务");
      } else {
      // 如果时间是偶数抛出异常, 由调用来处理
      throw new Error("当前时间为偶数无法执行任务");
      }
      }

      // 捕获处理异常
      try {
      something();
      } catch (error) {
      alert(error.message);
      }
  • 错误对象

    • message 属性: 错误相关信息
    • stack 属性: 函数调用栈记录信息

Promise 是什么?

  1. 抽象表达: Promise是JS中进行异步编程的新的解决方案

  2. 具体表达:

    • 从语法上来说: Promise是一个构造函数
    • 从功能上来说: promise对象用来封装一个异步操作并可以获取其结果
  3. promise的状态改变(只有2种, 只能改变一次)

    • pending变为resolved
    • pending变为rejected

promise的基本流程

初体验

  • 执行器函数: 同步调用

  • then是同步调用(取决于执行器的promise对象的状态)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    <script>
    // 1. 创建一个新的promise对象
    const p = new Promise((resolve, reject) => {// 执行器函数 同步回调
    console.log('执行 excutor')
    // 2. 执行异步操作任务
    setTimeout(() => {
    const time = Date.now() // 如果当前时间是偶数就代表成功, 否则代表失败
    // 3.1. 如果成功了, 调用resolve(value)
    if (time %2 == 0) {
    resolve('成功的数据, time=' + time)
    } else {
    // 3.2. 如果失败了, 调用reject(reason)
    reject('失败的数据, time=' + time)
    }
    }, 1000);

    })
    console.log('new Promise()之后')

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

为什么要用 Promise?

灵活指定回调函数

  • 指定回调函数的方式更加灵活: 可以在请求发出甚至结束后指定回调函数

  • 旧的: 必须在启动异步任务前指定

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    <script>
    // 成功的回调函数
    function successCallback(result) {
    console.log("声音文件创建成功: " + result);
    }
    // 失败的回调函数
    function failureCallback(error) {
    console.log("声音文件创建失败: " + error);
    }

    /* 使用纯回调函数 */
    createAudioFileAsync(audioSettings, successCallback, failureCallback)
    </script>
  • 使用Promise

    1
    2
    3
    4
    5
    const promise = createAudioFileAsync(audioSettings); // 假设2秒处理完成
    setTimeout(() => {
    // 可以在3秒之后再处理
    promise.then(successCallback, failureCallback);
    }, 3000);

链式调用解决回调地狱

  • 支持链式调用, 可以解决回调地狱问题

  • 回调地狱: 在js里,在异步js里,回调函数写的太多了,回调套回调。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    /* 
    回调地狱
    */
    doSomething(function (result) {
    doSomethingElse(
    result,
    function (newResult) {
    doThirdThing(
    newResult,
    function (finalResult) {
    console.log("Got the final result: " + finalResult);
    },
    failureCallback,
    );
    },
    failureCallback,
    );
    }, failureCallback);
  • 使用promise的链式调用解决回调地狱

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    doSomething()
    .then(function (result) {
    return doSomethingElse(result);
    })
    // 返回的是一个上一个异步操作的结果
    .then(function (newResult) {
    return doThirdThing(newResult);
    })
    .then(function (finalResult) {
    console.log("Got the final result: " + finalResult);
    })
    .catch(failureCallback);
  • async/await: 回调地狱的终极解决方案

1
2
3
4
5
6
7
8
9
10
async function request() {
try {
const result = await doSomething();
const newResult = await doSomethingElse(result);
const finalResult = await doThirdThing(newResult);
console.log("Got the final result: " + finalResult);
} catch (error) {
failureCallback(error);
}
}

如何使用 Promise

API

1. Promise构造函数: Promise (excutor) {}
        excutor函数: 同步执行  (resolve, reject) => {}
        resolve函数: 内部定义成功时我们调用的函数 value => {}
        reject函数: 内部定义失败时我们调用的函数 reason => {}
        说明: excutor会在Promise内部立即同步回调,异步操作在执行器中执行

2. Promise.prototype.then方法: (onResolved, onRejected) => {}
        onResolved函数: 成功的回调函数  (value) => {}
        onRejected函数: 失败的回调函数 (reason) => {}
        说明: 指定用于得到成功value的成功回调和用于得到失败reason的失败回调
              返回一个新的promise对象

3. Promise.prototype.catch方法: (onRejected) => {}
        onRejected函数: 失败的回调函数 (reason) => {}
        说明: then()的语法糖, 相当于: then(undefined, onRejected)

4. Promise.resolve方法: (value) => {}
        value: 成功的数据或promise对象
        说明: 返回一个成功/失败的promise对象

5. Promise.reject方法: (reason) => {}
        reason: 失败的原因
        说明: 返回一个失败的promise对象

6. Promise.all方法: (promises) => {}
        promises: 包含n个promise的数组
        说明: 返回一个新的promise, 只有所有的promise都成功才成功, 只要有一个失败了就直接失败
7. Promise.race方法: (promises) => {}
        promises: 包含n个promise的数组
        说明: 返回一个新的promise, 第一个完成的promise的结果状态就是最终的结果状态

Promise构造函数

  • 代码如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    new Promise((resolve, reject) => {
    setTimeout(() => {
    // resolve('成功的数据')
    reject("失败的数据");
    }, 1000);
    })
    .then((value) => {
    console.log("onResolved()1", value);
    })
    .catch((reason) => {
    console.log("onRejected()1", reason);
    });

resolve & reject方法

  • 创建一个成功的promise对象

    1
    2
    3
    4
    5
    6
    // 产生一个成功值为1的promise对象
    const p1 = new Promise((resolve, reject) => {
    setTimeout(() => {
    resolve(1);
    }, 100);
    });
  • 使用resolve,reject方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    // 产生一个成功值为2的promise对象
    const p2 = Promise.resolve(2);
    // 产生一个失败值为3的promise对象
    const p3 = Promise.reject(3);

    p1.then((value) => {
    console.log(value);
    });
    p2.then((value) => {
    console.log(value);
    });
    p3.catch((reason) => {
    console.log(reason);
    });

    // 结果文件:
    2;
    3;
    1;

all & race

  • 代码如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    const p4 = Promise.reject(4)
    // 情况一
    const pAll = Promise.all([p1, p2, p4, p3])
    // 情况二
    const pAll = Promise.all([p1, p2])
    pAll.then(
    values => {
    console.log('all onResolved()', values)
    },
    reason => {
    console.log('all onRejected()', reason)
    }
    )

    const pRace = Promise.race([p1, p2, p3])
    pRace.then(
    value => {
    console.log('race onResolved()', value)
    },
    reason => {
    console.log('race onRejected()', reason)
    }
    )

    // 第一种情况:有多个错误
    all onRejected() 4 // 返回第一个错误的结果
    race onRejected() 2 // 返回第一个执行完成的结果,全为rejected状态返回第一个结果
    // 第二种情况:全部正确
    race onResolved() 2 // 返回第一个执行完成的结果
    all onResolved() [1, 2] // 返回成功的数组结果

Promise理解

状态改变

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

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

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

  • 代码如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    const p = new Promise((resolve, reject) => {
    // resolve(1) // promise变为resolved成功状态
    // reject(2) // promise变为rejected失败状态
    // throw new Error('出错了') // 抛出异常, promse变为rejected失败状态, reason为 抛出的error
    throw 3; // 抛出异常, promse变为rejected失败状态, reason为 抛出的3
    });
    p.then(
    (value) => {},
    (reason) => {
    console.log("reason", reason);
    },
    );

指定多个成功/失败回调函数

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

  • 代码如下

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    const p = new Promise((resolve, reject) => {
    // resolve(1)
    // reject(2)
    // throw new Error('出错了')
    throw 3
    })
    p.then(
    value => {},
    reason => {console.log('reason', reason)}
    )
    p.then(
    value => {},
    reason => {console.log('reason2', reason)}
    )

    // 结果
    eason 3
    reason2 3

then()返回的结果状态

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

  • 详细表达:

    1. 如果抛出异常, 新promise变为rejected, reason为抛出的异常
    2. 如果返回的是非promise的任意值, 新promise变为resolved, value为返回的值
    3. 如果返回的是另一个新promise, 此promise的结果就会成为新promise的结果
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    new Promise((resolve, reject) => {
    // resolve(1)
    reject(1)
    }).then(
    value => {
    console.log('onResolved1()', value)
    // return 2
    // return Promise.resolve(3)
    // return Promise.reject(4)
    throw 5
    },
    reason => {
    console.log('onRejected1()', reason)
    // return 2
    // return Promise.resolve(3)
    // return Promise.reject(4)
    throw 5
    }
    ).then(
    value => {
    console.log('onResolved2()', value)
    },
    reason => {
    console.log('onRejected2()', reason)
    }
    )

    // 结果
    onRejected1() 1
    onRejected2() 5

顺序:状态改变和回调函数

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

  • 常规:指定回调函数, 后改变的状态

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    new Promise((resolve, reject) => {
    setTimeout(() => {
    resolve(1); // 后改变的状态(同时指定数据), 异步执行回调函数
    }, 1000);
    }).then(
    // 先指定回调函数, 保存当前指定的回调函数
    (value) => {
    console.log("value", value);
    },
    (reason) => {
    console.log("reason", reason);
    },
    );
  • 如何先改状态, 后指定回调函数?

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

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      // 如何先改状态, 后指定回调函数
      new Promise((resolve, reject) => {
      resolve(1) // 先改变的状态(同时指定数据)
      }).then(// 后指定回调函数, 异步执行回调函数
      value => {console.log('value2', value)},
      reason => {console.log('reason2', reason)}
      )
      console.log('-------')

      // 结果
      -------
      value2 1
    2. 延迟更长时间才调用then()

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      const p = new Promise((resolve, reject) => {
      setTimeout(() => {
      resolve(1); // 先改变的状态(同时指定数据), 异步执行回调函数
      }, 1000);
      });

      setTimeout(() => {
      p.then(
      (value) => {
      console.log("value3", value);
      },
      (reason) => {
      console.log("reason3", reason);
      },
      );
      }, 1100);

串连多个操作任务

  • promise的then()返回一个新的promise, 通过then的链式调用串连多个同步/异步任务

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    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

promise异常穿透

  • 当使用promise的then链式调用时, 可以在最后指定失败的回调,前面任何操作出了异常, 都会传到最后失败的回调中处理。

  • 如下面代码,执行器中是reject(1)执行的是then中reject方法,没有定义,会往下查找,最后执行到catch代码块中。

  • 默认不写reject的处理,可以理解这里有二种写法

    • 返回reject的promise
    • 抛除异常,返回reject的promise
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    new Promise((resolve, reject) => {
    // resolve(1)
    reject(1)
    }).then(
    value => {
    console.log('onResolved1()', value)
    return 2
    },
    // reason => {throw reason}
    ).then(
    value => {
    console.log('onResolved2()', value)
    return 3
    },
    reason => {throw reason}
    ).then(
    value => {
    console.log('onResolved3()', value)
    },
    reason => Promise.reject(reason)
    ).catch(reason => {
    console.log('onReejected1()', reason)
    })

    // 结果
    onReejected1() 1

中断promise链

  • 如果在catch后面添加.then后还是会急需执行

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    new Promise((resolve, reject) => {
    // resolve(1)
    reject(1)
    }).then(
    value => {
    console.log('onResolved1()', value)
    return 2
    },
    // reason => {throw reason}
    ).then(
    value => {
    console.log('onResolved2()', value)
    return 3
    },
    reason => {throw reason}
    ).catch(reason => {
    console.log('onReejected1()', reason)
    }).then(
    value => {
    console.log('onResolved3()', value)
    },
    reason => Promise.reject(reason)
    )

    // 结果
    onReejected1() 1 // 失败后的处理
    onResolved3() undefined // 在catch中没有返回值,默认是return undefined

async 与 await

async函数示例

  • 代码如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    async function fn1() {
    return 1
    // throw 2
    // return Promise.reject(3)
    // return Promise.resolve(3)
    /* return new Promise((resolve, reject) => {
    setTimeout(() => {
    resolve(4)
    }, 1000);
    }) */
    }


    const result = fn1()
    console.log(result)

    // 结果
    Promise {<fulfilled>: 1}
    __proto__: Promise
    [[PromiseState]]: "fulfilled"
    [[PromiseResult]]: 1
    // -------------------------
    Promise {<rejected>: 2}
    __proto__: Promise
    [[PromiseState]]: "rejected"
    [[PromiseResult]]: 2
    Uncaught (in promise) 2
    // -------------------------
    Promise {<pending>}
    __proto__: Promise
    [[PromiseState]]: "rejected"
    [[PromiseResult]]: 3
    Uncaught (in promise) 3
    // -------------------------
    Promise {<pending>}
    __proto__: Promise
    [[PromiseState]]: "fulfilled"
    [[PromiseResult]]: 3
    // -------------------------
    Promise {<pending>}
    __proto__: Promise
    [[PromiseState]]: "fulfilled"
    [[PromiseResult]]: 4

await表达式示例

  • 代码如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    function fn2() {
    return new Promise((resolve, reject) => {
    setTimeout(() => {
    // resolve(5)
    reject(6)
    }, 1000);
    })
    }

    async function fn3() {
    try {
    const value = await fn2() // await右侧表达为promise, 得到的结果就是promise成功的value
    console.log('value', value)
    } catch (error) {
    // 如果await的promise失败了, 就会抛出异常, 需要通过try...catch来捕获处理
    console.log('得到失败的结果', error)
    }

    fn3()

    // 结果
    value 5 // resolve(5)
    得到失败的结果 6 // reject(6)

    // 同时放开 resolve(5) reject(6)
    value 5 // 一个promise只能改变一次状态
  • await表达式右侧不是promise

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    function fn4() {
    return 6
    }

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

    fn3()

    // 结果
    value 6

JS 异步之宏队列与微队列

执行顺序

  1. 宏列队: 用来保存待执行的宏任务(回调), 比如: 定时器回调/DOM事件回调/ajax回调
  2. 微列队: 用来保存待执行的微任务(回调), 比如: promise的回调/MutationObserver的回调
  3. JS执行时会区别这2个队列
    • JS引擎首先必须先执行所有的初始化同步任务代码
    • 每次准备取出第一个宏任务执行前, 都要将所有的微任务一个一个取出来执行

练手1

  • 代码如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    <script>
    setTimeout(()=>
    {
    console.log(1) // 第一个宏任务
    }
    ,0) Promise.resolve().then(()=>
    {
    console.log(2) // 第一个微任务
    }
    ) Promise.resolve().then(()=>
    {
    console.log(4) // 第二个微任务
    }
    ) console.log(3) // 同步任务先输出
    </script>
  • 结果: 3 2 4 1

练手2

  • 代码如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    <script>
    setTimeout(() => {
    console.log(1) // 第一个宏任务
    }, 0)

    new Promise((resolve) => {
    console.log(2) // 同步执行
    resolve()
    }).then(() => {
    console.log(3) // 第一个微任务
    }).then(() => {
    console.log(4) // 第二个微任务
    })

    console.log(5) // 同步任务先输出
    </script>
  • 结果: 2 5 3 4 1

练手3

  • 代码如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    <script>
    // first函数 ,返回的是一个promise对象,结果为 resolve(2)
    const first = () => (new Promise((resolve, reject) => {
    // 同步代码优先输出
    console.log(3)
    // ---- start -----定义 Promise 实例对象 p。
    let p = new Promise((resolve, reject) => {
    console.log(7)
    setTimeout(() => {
    console.log(5)
    resolve(6)
    }, 0)
    resolve(1)
    })
    // ---- end -----
    resolve(2)

    p.then((arg) => {
    console.log(arg)
    })
    }))

    first().then((arg) => {
    console.log(arg)
    })
    console.log(4)
    </script>
  • 结果:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    /**
    定义了first函数 ,返回的是一个promise对象,结果为 resolve(2)
    1. first() 执行函数
    执行同步代码 输出3 ,
    2. 执行定义的promise的excute ,输出7
    定时器任务放到宏队列里,p的结果为reslove(1),then的代码放入微队列里,数据为1
    宏: [5]
    微: [1]

    3. first().then的输出(数据为2)放到第二个微队列里, 先执行最后console的同步任务,输出 4
    宏: [5]
    微: [1, 2]

    4. 先执行微队列里的 后执行宏队列 输出 1 2 5 p的结果不可更改

    结果为: 3 7 4 1 2 5
    */

练手4

  • 代码如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    <script>
    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")
    })
    </script>
  • 结果:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    /**
    1. 查看同步代码 有7 24 行先输出 1 7
    2. 定时器添加到宏任务,继续执行第一个promise的代码,将then的第一个异步操作放入微队列
    继续向下执行,将第二个promise的then异步操作放到微队列
    宏: [0 ]
    微: [2 8]
    3. 执行第一个微队列,根据8行的结果进入then,打印 2,创建promise对象,执行器打印 3,将打印4放入到微任务
    微: [8 4]
    4. 由于p1的then执行完成,将20行加入微队列
    微: [8 4 6 ]
    5. 继续执行微队列,打印 8
    微: [4 6 ]
    6. 继续执行微队列,打印 4,执行同步的then操作,将17行异步放入到微队列
    微: [6 5]
    7. 先微队列后宏队列,依次输出 6 5 0

    结果: 1 7 2 3 8 4 6 5 0
    */