Await操作符

await操作符只能在异步函数中使用,当你在一个异步操作之前放置await操作符,那么函数的执行流就会在此“等待”,直到异步结果可用时,才继续执行。比如,我们要异步读取文件内容,等内容完全读取,然后再将内容写入到另一个文件中;为此,我们可以定义一个readWrite函数,在它的内部,它会逐步执行异步操作:

code/async-await/read-write-file.js

async function readWrite() {
  const content = await readFile('./example.txt', 'utf-8')
  const result = await writeFile('./example-copy.txt', content)
  return result
}

由于readWrite使用了async关键字,因此可以在其函数体内使用await操作符,我们首先等待文件内容的读取,读取完毕后再异步执行写入操作,最后我们返回了异步操作的处理结果。

现在,我们再来看另外一个多个异步任务串行执行的例子,以下是各项操作的执行顺序:

  1. 发起Get请求到公用API获取一些新闻信息
  2. 列出文本文件下的文件列表,并选取以.txt结尾的文件
  3. 读取选取的文件内容,并把请求到的新闻信息附加到文件内容上
  4. 把最终的文件内容写入到本地文件final.txt

在下面的代码块中,你将会看到我们是如何使用await操作符来完成每一步异步操作的,它会等待异步操作的执行,直到取到操作结果才继续执行下一步:

code/async-await/post-body-example/main.js

async function main() {
  const response = await axios.get(
    'https://jsonplaceholder.typicode.com/posts/1'
  )
  const postBody = response.data.body
  const localFolderList = await readdir('.')
  const textFiles = localFolderList.filter(onlyTextFiles)
  const localFileContent = await readFile(textFiles[0], 'utf-8')
  const finalResult = localFileContent + postBody
  const writeResult = await writeFile('./final.txt', finalResult)
  return writeResult
}

乍一看,上面的代码像是同步的,但实际上并不是。每个任务执行的时候,并没有阻塞任何东西。这一点非常重要,异步代码不会阻塞任何将要被执行的操作,这对执行效率大有帮助。现代,让我们深入分析上面的代码。问问自己:哪些任务是能够独立处理的?哪些任务是需要按照特定顺序执行的?换句话说,我们是否可以把操作分成两个或者多个异步部分?一个可能的做法就是把它切分两个操作:

  1. 读取文件夹的内容,获取文本文件,读取文本文件的内容
  2. 发起Get请求获取新闻信息

简单的分析,你会发现,发起Get请求和读取文件信息是没有先后顺序的。然而,要读取本地文本内容,你需要先读取文件夹内容,并过滤出文本文件。现在,我们重新组织了需要完成的任务,我们可以使用Promise.all来并发执行任务:

code/async-await/post-body-example/main-group.js

async function readLocalContent() {
  const localFolderList = await readdir('.')
  const textFiles = localFolderList.filter(onlyTextFiles)
  const localFileContent = await readFile(textFiles[0], 'utf-8')
  return localFileContent
}
async function getPostObject() {
  const response = await axios.get(
    'https://jsonplaceholder.typicode.com/posts/1'
  )
  return response.data.body
}
async function main() {
  try {
    const results = await Promise.all([readLocalContent(), getPostObject()])
    const finalContent = results[0] + results[1]
    return writeFile('./final2.txt', finalContent)
  } catch (e) {
    return Promise.reject(e)
  }
}

在上面的代码中,我们把任务切分成两个异步函数来处理,这样我们就可以并发地执行它们。在main函数中,我们使用Promise.all来等待它们全部执行,然后把它们的结果写入到本地文件中。

用户头像
登录后发表评论