Published 2022-02-15

Async & Promise

tc1TS8

异步处理历史

优缺点对比:

发展史 优点 缺点
Callback 解决了同步问题 回调地狱、可读性差、无法 try / catch 、无法 return
Promise 一定程度上解决了回调地狱的可读性 无法取消、任务多时,同样存在语义不清晰
Generator 可以控制函数的执行,可以配合 co 函数库使用 流程管理却不方便(即何时执行第一阶段、何时执行第二阶段
async / await 语义更清晰、简洁,内置执行器 认知不清晰可能会造成大量 await 阻塞(程序并不会等在原地,而是继续事件循环,等到响应后继续往下走)情况

Promise

let promise = new Promise(function (resolve, reject) {
  // code
})
promise
  .then(() => {
    // then
  })
  .catch((error) => {
    // console.log(error)
  })
  .finally((_) => {
    // finally
  })

code处是用于执行的代码,当new Promise创建时,自动执行。

then是定义在Promise.prototype上的用来处理状态改变时的回调函数。

参数resolvereject是 JavaScript 自身提供的回调函数。当code呗执行后应该调用resolvereject

promisereject的时候或者运行代码抛出错误异常如:throw new Error('Whoops!')catch负责处理错误

finayllypromise结束时,无论结果是fulfilled还是rejected都会执行的回调函数

内部属性:

ZBHm59

Promise.all

执行多个 promise,并等待所有 promise 准备就绪,任意一个 promise 被 reject,都会立即出发 Promise.all 的 reject 并且返回该 promise 的 error

let promise = Promise.all([
  /*promises*/
])

// 例子
let urls = [
  'https://api.github.com/users/iliakan',
  'https://api.github.com/users/remy',
  'https://api.github.com/users/jeresig'
]

// 将每个 url 映射(map)到 fetch 的 promise 中
let requests = urls.map((url) => fetch(url))

// Promise.all 等待所有任务都 resolved
Promise.all(requests).then((responses) =>
  responses.forEach((response) => alert(`${response.url}: ${response.status}`))
)

Promise.allSettled

与 Promise.all 不同的是,Promise.allSettled 会等待所有 promise 完成,无论成功失败。

Promise.race

只要有一个准备就绪就返回其结果或者错误

Promise.race([
  new Promise((resolve, reject) => setTimeout(() => resolve(1), 1000)),
  new Promise((resolve, reject) =>
    setTimeout(() => reject(new Error('Whoops!')), 2000)
  ),
  new Promise((resolve, reject) => setTimeout(() => resolve(3), 3000))
]).then(alert) // 1

Promise.any

与 Promise.race 类似,Promise.any 等待的是第一个fulfilled,如果都rejected,则返回一个 error 数组

async/await

Async/await 是以更舒适的方式使用 promise 的一种特殊语法,同时它也非常易于理解和使用。

async 会将其后面的函数的返回值封装成一个Promise对象,而 await 会等待这个Promise完成,并将其结果返回。

async function hello() {
  return (greeting = await Promise.resolve('Hello'))
}

hello().then(alert)

错误处理

  1. 使用try...catch捕获 async/await 运行程序中抛出的错误
  2. await-to-js,使用类 go 语言的方式处理(属于 1 的封装)