如何通过三种方式编写异步 JavaScript 代码

2025-06-08

如何通过三种方式编写异步 JavaScript 代码

JavaScript 是一种单线程编程语言。同一时间只能执行一件事。不过,有一种方法可以解决这个问题。您可以编写异步 JavaScript 代码。本教程将帮助您做到这一点。它将概述编写异步代码的三种方法。

异步 JavaScript 简介

JavaScript 本质上是一种单线程编程语言。它运行在一个线程上。这个线程基于所谓的事件循环。当事件发生时,该线程会做出响应。作为一门单线程语言,JavaScript 一次只能处理一件事,也就是一条语句。在此期间,线程会被阻塞。

这有一些好处。它使编写代码变得更容易。例如,您不必担心与并发相关的问题。您的代码将按照您编写的顺序顺序运行。您也不必担心同时调用多个任务。

当然也有一些缺点。最大的缺点可能是每次只能调用一件事。之后的任何操作都必须等到该操作完成后才能执行。这在它看来可能不是什么问题,但一旦它真的成了问题,它就真的成了问题。例如,假设你有一个应用需要从某个 API 获取数据。

当您以同步方式调用 API 时,此调用将阻塞主线程,直到其完成为止。在此期间,其余代码必须等待,直到调用停止阻塞主线程。在此之前,您的应用将停止响应。

// Function to make an API call
function makeAPICall() {
  // Show notification about API call
  console.log('Calling some API.')

  // Get the data
  console.log('Data received from the API.')
}

// Function to process the API data
function processAPIData() {
  // Show notification about processing data
  console.log('Data processed.')
}

// Function to read the API data
function readTheData() {
  console.log('Reading the data.')
}

// Another app function
// This function has to wait until
// the makeAPICall() and processAPIData() are finished
function someOtherFunction() {
  console.log('Some other function not related to API.')
}

// Make the API call
makeAPICall()

// Process data from API
processAPIData()

// Read the data
readTheData()

// Run some other function
someOtherFunction()

// Output:
// 'Calling some API.'
// 'Data received from the API.'
// 'Data processed.'
// 'Reading the data.'
// 'Some other function not related to API.'
Enter fullscreen mode Exit fullscreen mode

相反的问题则是延迟。在这种情况下,你的代码可能会以与你预期不同的顺序运行。结果,你的程序的某些部分可能需要使用尚未可用的数据。

// Function to make an API call
function makeAPICall() {
  // Show notification about API call
  console.log('Calling some API.')
  // Simulate a delay
  setTimeout(() => {
    // Get the data
    console.log('Data received from the API.')

    // Show confirmation message
    console.log('API call finished.')
  }, 2000)
}

// Function to process the API data
function processAPIData() {
  // Show notification about processing data
  console.log('Data processed.')
}

// Function to read the API data
function readTheData() {
  console.log('Reading the data.')
}

// Another app function
function someOtherFunction() {
  console.log('Some other function not related to API.')
}

// Make the API call
makeAPICall()

// Process the data
processAPIData()

// Read the data
readTheData()

// Do some other stuff
someOtherFunction()

// Output:
// 'Calling some API.'
// 'Data processed.'
// 'Reading the data.'
// 'Some other function not related to API.'
// 'Data received from the API.'
// 'API call finished.'
Enter fullscreen mode Exit fullscreen mode

解决方案是编写异步 JavaScript 代码,使 API 调用异步化。编写异步 JavaScript 代码时,多个任务可以同时并发运行。运行某个异步任务时,它会被放入事件队列,因此不会阻塞主线程。

如果主线程未被阻塞,它可以执行后续任务。它可以处理你剩余的代码。当事件队列中的异步任务完成后,它会返回结果,以便你处理。实现这一点有三种方法:回调、Promises 和 async/await。

回调

编写异步 JavaScript 代码的第一个也是最古老的方法是使用回调。回调是一个异步函数,当你调用它时,它会作为参数传递给其他函数。当你调用的函数完成执行后,它会“回调”该回调函数。

在此之前,回调函数不会被调用。它什么也不做。最重要的是,回调函数不会阻塞主线程,因此主线程可以处理其他事情。一个仍然经常使用回调的例子是事件监听器

addEventListener()方法接受三个参数。第一个参数是您想要监听的事件类型。第二个参数是您想要在特定事件发生时执行的回调函数。第三个参数是可选的,是一个带有选项的对象。当事件发生时,您提供的回调函数将被调用。

// Find a button in the dom
const btn = document.querySelector('#btn')

// Create handler function
function handleBtnClick() {
  console.log('Click!')
}

// Attach event listener to the btn,
// add pass in the handler function as a callback
// that will be invoked when someone clicks the button
btn.addEventListener('click', handleBtnClick)

// Alternative:
// Write the callback function directly
btn.addEventListener('click', function() {
  console.log('Click!')
})
Enter fullscreen mode Exit fullscreen mode

当你无法预测某些数据何时可用时,回调尤其有用。以 API 调用、数据处理和延迟为例。我们无法预测 API 何时完成,同样也无法预测数据处理何时完成。

使用回调函数,你无需尝试预测任何事情。你只需按照所需的顺序编写函数即可。例如,如果处理 API 数据需要时间,你可以将读取这些数据的函数作为回调传递,并在数据准备就绪时执行。在此之前,它不会阻塞任何操作。

// Create a function to make an API call
function makeAPICall() {
  // Show notification about API call
  console.log('Calling some API.')

  // Simulate a delay
  setTimeout(() => {
    // Get the data
    console.log('Data received from the API.')

    // Process received data
    processAPIData()

    // Show confirmation message
    console.log('API call finished.')
  }, 2000)
}

// Create a function to process the API data
function processAPIData() {
  // Show notification about processing data
  console.log('Data processed.')

  readTheData()
}

// Create a function to read the API data
function readTheData() {
  console.log('Reading the data.')
}

// Create another app function
// This function will be invoked
// right after the makeAPICall() function
// and before all other functions
function someOtherFunction() {
  console.log('Some other function not related to API.')
}

// Make the API call
makeAPICall()

// Run some other function
someOtherFunction()

// Output:
// 'Calling some API.'
// 'Some other function not related to API.'
// 'Data received from the API.'
// 'Data processed.'
// 'Reading the data.'
// 'API call finished.'
Enter fullscreen mode Exit fullscreen mode

承诺

编写异步 JavaScript 代码的第二种方法是 Promises。Promises 是一项较新的功能,随ES6 规范引入 JavaScript 。它提供了一种非常简便的方法来处理异步 JavaScript 代码。这也是许多 JavaScript 开发人员(如果不是几乎所有的话)开始使用 Promises 而不是回调的原因之一。

Promise是一个代表某个值的对象。这个值在创建 Promise 时是未知的,会在未来的某个时刻被知晓。Promise 会通过“fulfilled”或“rejected”状态返回这个值。“fulfilled”表示 Promise 成功。“rejected”表示 Promise 由于某种原因失败了。

Promise 的状态为“fulfilled”或“rejected”,即“settled”。在 Promise 状态为“settled”之前,它处于 pending 状态。Promise 可以处于以下四种状态:pending、“fulfilled”、“rejected”和“settled”。您可以使用三个处理函数来获取 Promise 的返回值。

这些处理函数包括then()catch()finally()。使用这些处理函数的方法是将它们附加到 Promise 对象。根据 Promise 的状态,将调用其中一个处理函数。then()当 Promise 状态为“fulfilled”时,将调用 ,但您也可以使用它来处理“rejected”状态。

仅当 Promise 状态为“rejected”时才会调用catch()。最后一个,finally(),将在 Promise 状态为“settled”时调用。这也意味着finally(),无论 Promise 状态是“fulfilled”还是“rejected”, 每次都会被调用。要了解更多关于 Promise 的信息,请查看这篇专门的教程。

// Create new Promise to make the API call
const makeAPICall = new Promise((resolve, reject) => {
  // Show notification about API call
  console.log('Calling some API.')

  setTimeout(() => {
    // Get the data
    console.log('Data received from the API.')

    // Process received data
    resolve('API call finished.')
  }, 2000)
})

// Create a function to process the API data
function processAPIData() {
  // Show notification about processing data
  console.log('Data processed.')
}

// Create a function to read the API data
function readTheData() {
  // Process received data
  console.log('Reading the data.')
}

// Add some additional function
// This function will be able to run
// right after the makeAPICall Promise
// and before all other functions
function someOtherFunction() {
  console.log('Some other function not related to API.')
}

// Make the API call
makeAPICall
  // And handler for fulfilled state of the Promise
  .then(resOne => {
    // Log the message from makeAPICall Promise
    console.log(resOne)

    // Process the data
    processAPIData()

    // Read the data
    readTheData()
  })
  // And handler for rejected state of the Promise
  .catch(error => {
    console.log(`There has been an error during the API call: ${error}.`)
  })
  // Optionally, you could add finally() here
  // .finally(() => {})

// Run some other function
someOtherFunction()

// Output:
// 'Calling some API.'
// 'Some other function not related to API.'
// 'Data received from the API.'
// 'API call finished.'
// 'Data processed.'
// 'Reading the data.'
Enter fullscreen mode Exit fullscreen mode

异步/等待

编写异步 JavaScript 代码的最后一个选项是使用 async/await。async/await 是在 ES8 中引入的。async/await 由两部分组成。第一部分是一个async函数。这个 async 函数默认异步执行。它返回的值是一个新的 Promise。

这一点很重要。由于返回的值是 Promise 类型的,这意味着你必须使用 Promise 的处理函数才能处理该值。这些处理函数就是then()在上一节关于 Promise 的部分中已经见过它们。catch()finally()

async/await 的第二部分是await操作符。该操作符与 Promise 一起使用。它的作用是使异步函数暂停,直到后面的 Promise 得到解决(即 fulfilled 或 rejected)。当 Promise 执行完毕时,它会从 Promise 中提取值,并让异步函数继续执行。

异步函数是异步的。当异步函数被await操作符暂停时,其余代码不会停止。该函数不会阻塞主线程。因此,JavaScript 可以继续执行其余代码。当等待的 Promise 得到解决后,异步函数将恢复执行并返回已解析的值。

关于 ,需要记住一件重要的事情await。此运算符只能在 async 函数内部使用。如果您尝试在其他地方使用它,JavaScript 将抛出语法错误。如果您想了解更多关于 async/await 工作原理的信息,请查看这个详细的教程

// Create an async function
async function makeAPICall() {
  // Show notification about API call
  console.log('Calling some API.')

  // Create a Promise to make the API call
  const dataPromise = new Promise((resolve, reject) => {
    setTimeout(() => {
      // Get the data
      console.log('Data received from the API.')

      // Process received data and resolve the Promise
      resolve('API call finished.')
    }, 2000)
  })

  // Await for the data, the Promise to be settled,
  // return the from the async function as a new Promise
  return dataReceived = await dataPromise
}

// Create a function to process the API data
function processAPIData() {
  // Show notification about processing data
  console.log('Data processed.')
}

// Function to read the API data
function readTheData() {
  // Process received data
  console.log('Reading the data.')
}

// Add some additional function
// This function will be able to run
// right after the makeAPICall async function
// and before all other functions
function someOtherFunction() {
  console.log('Some other function not related to API.')
}

// Make the API call
// NOTE: makeAPICall() is async function
// and as a function it has to be invoked (by adding '()')
makeAPICall()
  // And handler for fulfilled state of the Promise
  .then((resOne) => {
    // Log the message from makeAPICall Promise
    console.log(resOne)

    // Process the data
    processAPIData()

    // Read the data
    readTheData()
  })
  // And handler for rejected state of the Promise
  .catch((error) => {
    console.log(`There has been an error during the API call: ${error}.`)
  })
// Optionally, you could add finally() here
// .finally(() => {})

// Run some other function
someOtherFunction()

// Output:
// 'Calling some API.'
// 'Some other function not related to API.'
// 'Data received from the API.'
// 'API call finished.'
// 'Data processed.'
// 'Reading the data.'
Enter fullscreen mode Exit fullscreen mode

结论:三种编写异步 JavaScript 代码的方法

是的,JavaScript 是一门单线程编程语言。然而,这并不意味着你不能编写异步代码。你可以,而且它可能不像人们想象的那么难和复杂。我希望本教程能让你很好地了解如何编写异步 JavaScript 代码。

鏂囩珷鏉ユ簮锛�https://dev.to/alexdevero/how-to-write-asynchronous-javascript-code-in- Three-ways-548i
PREV
即将推出的值得关注的 JavaScript ES2021(ES12)功能
NEXT
如何创建自己的 React 自定义 Hooks