# 一、async 和 async

# 1、Async 函数

MDN 描述 (opens new window)

  该函数返回的是一个 promise 对象。

async function Fn() {
  // return 1
  // throw 2
  // return Promise.resolve(3)
  return Promise.reject(4)
}

console.log(Fn())

Fn()
  .then((res) => {
    console.log('onFulfillment', res)
  })
  .catch((err) => {
    console.log('onRejection', err)
  })

  观察发现,它和我们前面学到 Promise.then()有很多相似之处:

new Promise((resolve, reject) => {
  // resolve(1)
  reject(2)
})
  .then((res) => {
    console.log('onFulfillment', res)
  })
  .catch((err) => {
    console.log('onRejection', err)
  })

  那使用 async 函数有什么用处呢?

当它结合后面的 await 时,就知道它有多么优秀了。

# 2、await 操作符

提示

  await 必须写在 async 函数中,但 async 函数中可以没有 await

MDN 描述 (opens new window)

  在传统的 Promise 中,如果我们仅仅想要回去成功回调的返回值,有没有更加简洁的写法。

  • 以前
new Promise((resolve, reject) => {
  resolve('success')
}).then((res) => {
  console.log('操作成功:', res)
})
  • 现在

await 后面通常跟的是一个 Promise 对象

async function fn1() {
  const res = await Promise.resolve(4)
}
fn1()

  那怎么处理,失败回调呢?

async function fn1() {
  try {
    const res = await Promise.reject(4)
  } catch (err) {
    console.log(err)
  }
}
fn1()

# 3、Async / await ✨

  现在我们已经知道了 async 函数返回的是一个 Promise,await 后面可以跟一个 Promise 的成功回调结果。

  现在我们综合一下看看:

async function fn1() {
  const res = await Promise.resolve(4)

  return res
}

fn1()
  .then((res) => {
    console.log('onFulfillment', res)
  })
  .catch((err) => {
    console.log('onRejection', err)
  })

利用 async 和 await 各自的特点,我们貌似达到了将异步任务放在 async 函数中同步执行的效果 🤔。

代码体验
async function test() {
  var res = await new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve('data')

      console.log('1111') // ①
    })
  })

  console.log('2222') // ②

  return res // ③
}

test()
  .then((res) => {
    console.log(res)
  })
  .catch((err) => {
    console.log(err)
  })

执行结果:

1111
2222
data
  • 解决回调地狱
async function fn1() {
  const res1 = await Promise.resolve(1)
  const res2 = await Promise.resolve(4 + res1)

  console.log('---- | ---')

  return res2
}

console.log(fn1())

// Promise {<pending>}
// ---- | ---

# 二、事件循环机制(EventLoop)

  JavaScript 是一门单线程执行的编程语言。也就是说,同一时间只能做一件事情。

但是他的运行环境浏览器确不是单线程的。

# 1、执行流程

  为了防止某个耗时任务导致程序假死的问题,JavaScript 包待执行任务分为:异步任务(非耗时) 和 同步任务(耗时)。

同步代码交给 浏览器的 JS 引擎执行,异步代码先交给宿主环境(浏览器/Node)相应的 Web APIs 模块管理执行。

  在宿主环境中已经完成的异步任务会被加入到消息队列中等待执行。

消息队列中如果存在微任务队列,则该任务队列会被优先放到栈中执行

  JavaScript 主线程从“消息队列”中读取异步任务的回调函数,放到执行栈中依次执行。这种不断循环运行的机制又被称为 EventLoop(事件循环)

注意:Promise 本身是同步的,但是 then 和 catch 是异步的

# 2、经典面试题

// 宏任务
setTimeout(function () {
  console.log('1')
})

new Promise(function (resolve) {
  console.log('2')
  resolve()
}).then(function () {
  // 微任务
  console.log('3')
})

console.log('4')

// 执行结果为: 2431

# 3、ajax 作用域 🎈

  下面简单的描述一个问题:

// 全局作用域
let data = {}

// 发起Ajax请求
fetch('https://jsonplaceholder.typicode.com/users/1')
  .then((res) => res.json())
  .then((res) => {
    data = res
  })

console.log(data) // {}

  那如何解决呢?

方案 1:XHR 同步请求
let data = {}

var xhr = new XMLHttpRequest()
xhr.open('GET', 'https://jsonplaceholder.typicode.com/users/1', false) // 同步请求
xhr.send()
if (/^2\d{2|$/.test(xhr.status)) {
  data = JSON.parse(xhr.responseText)
}

console.log(data) // {id: 1, name: 'Leanne Graham', username: 'Bret', email: '[email protected]', address: {…}, …}
方案 2: async / await 异步控制
async function demo() {
  let data = {}

  data = await fetch('https://jsonplaceholder.typicode.com/users/1').then((res) => res.json())

  console.log(data) // {id: 1, name: 'Leanne Graham', username: 'Bret', email: '[email protected]', address: {…}, …}
}
demo()
更新于 : 8/7/2024, 2:16:31 PM