《javascript高级程序设计》学习笔记 | 11.3.异步函数

关注前端小讴,阅读更多原创技术文章

异步函数

  • ES8 新增异步函数(async/await),是 ES6 期约模式在 ECMAScript 函数中的应用
  • 同步方式的代码执行异步

相关代码 →

异步函数

  • ES8 对函数进行了扩展,新增 2 个关键字asyncawait

async

  • async关键字用于声明异步函数,可用在函数声明函数表达式箭头函数方法
async function foo() {} // 用在函数声明
let bar = async function () {} // 用在函数表达式
let baz = async () => {} // 用在箭头函数
class Qux {
  async qux() {} // 用在方法
}
  • async关键字让函数具有异步特性,代码仍同步求值,参数或闭包也具有普通 JS 函数的正常行为
async function foo() {
  console.log(1)
}
foo()
console.log(2)
/* 
  1,foo()函数先被求值
  2
*/
  • 异步函数return返回的值,会被Promise.resolve()包装成期约对象,调用异步函数始终返回该期约对象

    • return关键字返回的是实现thenable接口的对象(callback、期约),该对象由提供给then()的处理程序解包
    • return关键字返回的是常规的值,返回值被当作已解决的期约(无return关键字,返回值被当作 undefined)
async function foo() {
  return 'foo' // 返回原始值
}
console.log(foo()) // Promise {: "foo"},被当作已解决的期约
foo().then((result) => console.log(result)) // 'foo'

async function bar2() {
  return ['bar'] // 返回没有实现thenable接口的对象
}
console.log(bar2()) // Promise {: ['bar']},被当作已解决的期约
bar2().then((result) => console.log(result)) // ['bar']

async function baz2() {
  const thenable = {
    then(callback) {
      callback('baz')
    },
  }
  return thenable // 返回实现了thenable接口的非期约对象
}
console.log(baz2()) // Promise {}
baz2().then((result) => console.log(result)) // 'baz',由then()解包

async function qux() {
  return Promise.resolve('qux') // 返回解决的期约
}
console.log(qux()) // Promise {}
qux().then((result) => console.log(result)) // 'qux',由then()解包

async function rejectQux() {
  return Promise.reject('qux') // 返回拒绝的期约
}
console.log(rejectQux()) // Promise {}
rejectQux().then(null, (result) => console.log(result)) // 'qux',由then()解包
// Uncaught (in promise) qux
rejectQux().catch((result) => console.log(result)) // 'qux',由catch()解包
  • 异步函数中抛出错误会返回拒绝的期约
async function foo() {
  console.log(1)
  throw 3
}
foo().catch((result) => console.log(result)) // 给返回的期约添加拒绝处理程序
console.log(2)
/* 
  1,foo()函数先被求值
  2
  3
*/
  • 异步函数中拒绝期约的错误(非“返回拒绝的期约”)不会被异步函数捕获
async function foo() {
  Promise.reject(3) // 拒绝的期约(非返回)
}
foo().catch((result) => console.log(result)) // catch()方法捕获不到
// Uncaught (in promise) 3,浏览器消息队列捕获

await

  • 使用await关键字可以暂停异步函数代码执行,等待期约解决
let p = new Promise((resolve, reject) => {
  setTimeout(resolve, 1000, 3)
})
p.then((x) => console.log(x)) // 3

// 用async/await重写
async function foo() {
  let p = new Promise((resolve, reject) => {
    setTimeout(resolve, 1000, 3)
  })
  console.log(await p)
}
foo() // 3
  • await会尝试解包对象的值(与yield类似),然后将该值传给表达式,而后异步恢复执行异步函数
async function foo() {
  console.log(await Promise.resolve('foo')) // 将期约解包,再将值传给表达式
}
foo()

async function bar2() {
  return await Promise.resolve('bar')
}
bar2().then((res) => console.log(res)) // 'bar'

async function baz2() {
  await new Promise((resolve, reject) => {
    setTimeout(resolve, 1000)
  })
  console.log('baz')
}
baz2() // 'baz'(1000毫秒后)
  • await根据等待的值,执行不同的操作

    • 若等待的值是实现thenable接口的对象(callback、期约),该对象由await解包
    • 若等待的值是常规值,该值被当作已解决的期约(然后再由await来解包)
async function foo() {
  console.log(await 'foo') // 等待原始值,被当作已解决的期约Promise.resolve('foo'),再由await解包
}
foo() // 'foo'

async function bar2() {
  console.log(await ['bar']) // 等待值是没有实现thenable接口的对象,被当作已解决的期约再由await解包
}
bar2() // ["bar"]

async function baz2() {
  const thenable = {
    then(callback) {
      callback('baz')
    },
  }
  console.log(await thenable) // 等待值是实现了thenable接口的非期约对象,由await解包
}
baz2() // 'baz'

async function qux() {
  console.log(await Promise.resolve('qux')) // 等待值是解决的期约
}
qux() // 'qux'
  • 等待会抛出错误的同步操作,会返回拒绝的期约
async function foo() {
  console.log(1)
  await (() => {
    throw 3 // 抛出错误的同步操作
  })()
}
foo().catch((result) => console.log(result)) // 给返回的期约添加拒绝处理程序
console.log(2)
/* 
  1
  2
  3
*/
  • 拒绝的期约使用await,会释放错误值(将拒绝期约返回)
async function foo() {
  console.log(1)
  await Promise.reject(3) // 对拒绝的期约使用await,将其返回(后续代码不再执行)
  console.log(4) // 不执行
}
foo().catch((result) => console.log(result)) // 给返回的期约添加拒绝处理程序
console.log(2)
/* 
  1
  2
  3
*/

await 的限制

  • 必须异步函数中使用
  • 不能在顶级上下文(如

你可能感兴趣的:(《javascript高级程序设计》学习笔记 | 11.3.异步函数)