【慕课网】Promise 入门教程

警告
本文最后更新于 2020-03-02,文中内容可能已过时。

讲师:翟路佳 课程:https://www.imooc.com/learn/949 代码:https://github.com/merrier/imooc-promise-sample

  • 了解 Promise 诞生的历史背景
  • 学会使用 Promise 解决异步回调带来的问题
  • 掌握 Promise 的进阶用法

按照用途来解释

  • 主要用于异步计算
  • 可以将异步操作队列化,按照期望的顺序执行,返回复合预期的结果。
  • 可以在对象之间传递和操作 Promise,帮助我们处理队列。
  • JavaScript 包含大量异步操作
  • 有了 Node.js 之后,对异步的依赖进一步加剧了(无阻塞高并发,是 Node.js 的招牌;异步操作是其保障;大量操作依赖回调函数)
  • 事件侦听与相应
  • 回调
  • 不好维护
  • 异步回调函数会在一个新的栈运行,所以无法获取之前的栈的信息;之前的栈也无法捕获这个栈抛出的错误信息。所以没法正常使用 try catch

总结如下

  • 嵌套层次很深,难以维护
  • 无法正常使用 return 和 throw
  • 无法正常检索堆栈信息
  • 多个回调之间难以建立联系

使用之前,初始化 Promise 实例

new Promise(
  /* 执行器executor */
  function (resolve, reject) {
    //一段耗时很长的异步操作

    resolve(); //数据处理完成

    reject(); //数据处理出错
  }
).then(
  function A() {
    //调用resolve()成功,下一步
  },
  function B() {
    //调用reject()或抛出错误,做相应处理
  }
);
  • Promise 是一个代理对象,它和原先要执行的操作并无关系。
  • 它通过引入一个回调,避免更多的回调。
  • Promise 有三个状态:
    • pending[待定]初始状态
    • fulfilled[实现]操作成功
    • rejected[被否决]操作失败
  • Promise 状态发生改变,就会触发.then()里的响应函数处理后续步骤。
  • Promise 状态一经改变,不会再变。
  • Promise 实例一经创建,执行器立即执行。

timeout.js

timeout2.js

fulfilled-then.js 在任何地方生成一个 Promise 队列后,可以把它作为一个变量传递到其他地方,不管前面 Promise 队列是否完成,队列都会按照追加的 then 来执行。

timeout3.js 在 Promise 里,如果不直接返回一个 Promise 实例,那么它就会默认执行下一个环节,即使返回了 false,也不影响下一步,因为 false 会直接传递到下一环节里;如果没有明确返回值,相当于返回 undefined

  • .then()接受两个函数作为参数,分别代表 fulfilled 状态下的响应函数和 rejected 状态下的响应函数。
  • .then()返回一个新的 Promise 实例,所以它可以链式调用。
  • 当前面的 Promise 状态改变时,.then()根据其最终状态,选择特定的状态响应函数执行。
  • 状态响应函数可以返回新的 Promise,或其它值
  • 如果返回新的 Promise,那么下一级.then()会在新 Promise 状态改变之后执行。
  • 如果返回其它任何值,则会立刻执行下一级.then()。

nested-then.js .then()里有.then()的情况

  • 因为.then()返回的还是 Promise 实例
  • 会等里面的.then()执行完,再执行外面的
  • 最好将其展开,会更好读

问题:下面的四种 Promise 的区别是什么

//# 1
doSomething()
  .then(function () {
    return doSomethingElse();
  })
  .then(finalHandler);

执行顺序:

doSomething
doSomethingElse(undefined)
finalHandler(resultOfDoSomthingElse)
//#2
doSomething()
  .then(function () {
    doSomethingElse();
  })
  .then(finalHandler);

执行顺序:

doSomething
doSomethingElse(undefined)
finalHandler(resultOfDoSomthingElse)
//#3
doSomething().then(doSomethingElse()).then(finalHandler);

执行顺序:

doSomething
doSomethingElse(undefined)
finalHandle(resultOfDoSomething)
//#4
doSomething().then(doSomethingElse).then(finalHandler);

执行顺序:

doSomething
doSomethingElse(resultOfDoSomething)
finalHandler(resultOfDoSomethingElse)

error.js error-reject.js Promise 会自动捕获内部异常,并交给 rejected 响应函数处理。

  • reject(‘错误信息’).then(null,message=>{})
  • throw new Error(‘错误信息’).catch(message=>{})
  • 推荐使用第二种,更加清晰好读,并且可以捕获前面的错误。

catch-then.js catch 也会返回一个 Promise 实例,并且其中没有抛出错误的话,它返回的 Promise 实例是 fulfilled 状态的

  • 强烈建议在所有队列最后都加上.catch(),以避免漏掉错误处理造成意想不到的问题。

批量执行

  • Promise.all([p1,p2,p3,……])用于将多个 Promise 实例,包装成一个新的 Promise 实例
  • 返回的实例是一个新的普通的 Promise
  • 它接受一个数组作为参数
  • 数组里可以是 Promise 对象,也可以是别的值,只有 Promise 会等待状态改变
  • 当所有子 Promise 都完成,该 Promise 完成,返回值是全部值的数组
  • 任何一个失败,该 Promise 失败,返回值是第一个失败的子 Promise 的结果 详见 all.js

Promise.all()最常见就是和.map()连用 map.js