Skip to main content

Promise

· 3 min read
Lex
Front End Engineer @ Baoxiaohe
  • What's Promise?
  • Why the Promise?
  • How using Promise?

Prepare#

函数对象与实例对象#

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

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

function Fn(){} // Fn函数
cosnt fn = new Fn() // Fn是构造函数 fn是实例对象(简称对象)console.log(Fn.prototype) // Fn是函数对象Fn.bind({}) // Fn是函数对象$('#test') // jQuery函数$.get('/test') // jQuery函数对象

回调函数的分类#

Callback function 自己定义,不用亲自调用(无法决定调用时间),会执行。

  • 同步回调:
    • 立即执行, 完全执行完了才结束, 不会放入回调队列中
    • e.g.
      • 数组遍历相关的回调函数
      • Promise 的 excutor 函数
const arr = [1, 2, 5];// 遍历回调,同步回调函数,不会放入回调队列arr.forEach((item) => {  console.log(item);});console.log("end"); // 1,2,5,end
  • 异步回调:
    • 不会立即执行,放入回调队列,所有同步执行完后才可能执行
    • e.g.
      • 定时器回调
      • ajax 回调
      • Promise 的成功|失败的回调
setTimeout(() => {  console.log("timeout callback()");}, 0);console.log("end"); // end,timeout callback()

Promise 的理解和使用#

Promise 是什么?#

Promise 是 JS 中进行异步编程的新的解决方案(旧的 ☞ 回调机制)

Promise 是一个构造函数

promise 对象用来封装一个异步操作并可以获取其结果

promise 的状态改变(只有 2 种, 只能改变一次)

  • pending 变为 resolved 返回的结果数据一般称 value
  • pending 变为 rejected 返回的结果数据一般称 reason

promise 的基本流程

promise基本流程

基本使用#

const p = new Promise((resolve, reject) => {  // excutor function 执行异步操作  setTimeout(() => {    const time = Date.now();    // 成功调用 resolve(value)    if (time % 2 === 0) resolve("success,time=" + time);    // 失败调用 reject(reason)    else reject("fail,time=" + time);  }, 1000);});
p.then(  // onResolved  (value) => {    console.log("成功的回调", value);  },  // onRejected  (reason) => {    console.log("失败的回调", reason);  });

为什么要用 Promise?#

  • 指定回调函数的方式更加灵活
    • 纯回调:必须在异步任务之前指定回调函数,
    • Promise:启动异步任务 => return promise object => bind callback function(甚至可以在异步任务结束后)
  • 支持链式调用, 可以解决回调地狱问题

如何使用 Promise?#

  • 主要 API
    • Promise 构造函数: Promise (excutor) {}
    • Promise.prototype.then 方法: (onResolved, onRejected) => {}
    • Promise.prototype.catch 方法: (onRejected) => {}
    • Promise.resolve 方法: (value) => {}
    • Promise.reject 方法: (reason) => {}
    • Promise.all 方法: ([promises]) => {}
    • Promise.race 方法: ([promises]) => {}
  • 几个重要问题
    • 如何改变 promise 的状态?
    • 一个 promise 指定多个成功/失败回调函数, 都会调用吗?
    • promise.then()返回的新 promise 的结果状态由什么决定?
    • 改变 promise 状态和指定回调函数(then())谁先谁后?
    • promise 如何串连多个操作任务?
    • promise 异常穿透?
    • 中断 promise 链

自定义 Promise#

    1. 定义整体结构
    1. Promise 构造函数的实现
    1. promise.then()/catch()的实现
    1. Promise.resolve()/reject()的实现
    1. Promise.all/race()的实现
    1. Promise.resolveDelay()/rejectDelay()的实现(DIY 扩展)
    1. ES6 class 版本

代码#

https://github.com/zhang13pro/Promise-DIY

async 与 await#

async 函数#

  • 函数的返回值为 promise 对象
  • promise 对象的结果由 async 函数执行的返回值决定

await 表达式#

  • await 右侧的表达式一般为 promise 对象, 但也可以是其它的值
  • 如果表达式是 promise 对象, await 返回的是 promise 成功的值
  • 如果表达式是其它值, 直接将此值作为 await 的返回值

注意:#

  • await 必须写在 async 函数中, 但 async 函数中可以没有 await
  • 如果 await 的 promise 失败了, 就会抛出异常, 需要通过 try...catch 来捕获处理

JS 异步之宏队列与微队列#

宏队列与微队列

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