Home > Web Front-end > JS Tutorial > Flow Control in JavaScript: Callbacks, Promises, async/await

Flow Control in JavaScript: Callbacks, Promises, async/await

Lisa Kudrow
Release: 2025-02-11 08:26:16
Original
142 people have browsed it

Flow Control in JavaScript: Callbacks, Promises, async/await

Key points of JavaScript asynchronous programming

This article will discuss JavaScript asynchronous programming in an easy-to-understand manner, covering three main methods: callback function, Promise and async/await. We will help you master the core concepts of JavaScript asynchronous programming through sample code, key points summary and in-depth learning resource links.

Summary of content:

  1. Single-threaded processing
  2. Use callback function to implement asynchronous operation
    • Callback Hell
  3. Promise
    • Async chain call
    • The future of Promise?
  4. async/await
    • Upgrade of Promise
    • Limitations of try/catch
  5. JavaScript Asynchronous Programming Journey

Async features of JavaScript

JavaScript is often referred to as an "asynchronous" language. what does that mean? How does it affect development? What changes have occurred in its methods in recent years?

Consider the following code:

result1 = doSomething1();
result2 = doSomething2(result1);
Copy after login
Copy after login
Copy after login

Most languages ​​process every line of code synchronously. The first line runs and returns the result, and the second line will only run after the first line is completed, regardless of how long it takes for the first line.

Single-threaded processing

JavaScript runs on a single thread. When executed in the browser tab, all other operations stop. This is necessary because changes to the page DOM cannot occur on parallel threads; it will be dangerous if one thread redirects to a different URL while another thread tries to attach child nodes.

Users rarely notice this because the processing proceeds quickly in small blocks. For example, JavaScript detects a button click, runs the calculation, and updates the DOM. Once done, the browser can process the next item in the queue.

(Note: Other languages, such as PHP, also use single threads, but may be managed by multi-threaded servers (such as Apache). Two simultaneous requests for the same PHP page can start two threads and run PHP run quarantine instance. )

Use callback function to implement asynchronous operation

Single threading brings a problem. What happens when JavaScript calls a "slow" process, such as Ajax requests from a browser or database operations on the server? This operation can take seconds or even minutes. The browser will be locked while waiting for a response. On the server, the Node.js application will not be able to process further user requests.

The solution is asynchronous processing. Instead of waiting for completion, it tells a process to call another function when the result is ready. This is called a callback function, which is passed as an argument to any asynchronous function.

Example:

doSomethingAsync(callback1);
console.log('finished');

// 当doSomethingAsync完成时调用
function callback1(error) {
  if (!error) console.log('doSomethingAsync complete');
}
Copy after login
Copy after login
Copy after login

doSomethingAsync function accepts a callback function as an argument (only passing a reference to the function, so the overhead is small). It doesn't matter how long doSomethingAsync takes; we only know that callback1 will be executed at some point in the future. The console will display:

result1 = doSomething1();
result2 = doSomething2(result1);
Copy after login
Copy after login
Copy after login

You can read more about callback functions: Understand JavaScript callback functions

Callback hell

Usually, the callback function is called only by one asynchronous function. Therefore, a concise anonymous inline function can be used:

doSomethingAsync(callback1);
console.log('finished');

// 当doSomethingAsync完成时调用
function callback1(error) {
  if (!error) console.log('doSomethingAsync complete');
}
Copy after login
Copy after login
Copy after login

A series of asynchronous calls can be completed by nesting callback functions. For example:

<code>finished
doSomethingAsync complete</code>
Copy after login
Copy after login

Unfortunately, this introduces callback hell - a notorious concept that even has its own webpage! The code is hard to read and gets worse when adding error handling logic.

Callback hell is relatively rare in client encoding. If you are making an Ajax call, updating the DOM and waiting for the animation to complete, it may go into two to three layers, but is usually still manageable.

For operating system or server processes, the situation is different. Node.js API calls may receive file uploads, update multiple database tables, write logs, and make further API calls before sending a response.

You can read more about callback hell: Say goodbye to callback hell

Promise

ES2015 (ES6) introduces Promise. The underlying layer still uses callback functions, but Promise provides a clearer syntax to chainedasynchronous commands, making them run in order (more on the next section).

In order to enable Promise-based execution, asynchronous callback-based functions must be changed so that they immediately return a Promise object. The object promises to run one of two functions at some point in the future (passed as a parameter):

  • resolve: handles the callback function that runs when successful completion
  • reject: Optional callback function running when processing fails

In the following example, the database API provides a connect method that accepts callback functions. The external asyncDBconnect function returns a new promise immediately and runs resolve or reject after a connection is established or failed:

doSomethingAsync(error => {
  if (!error) console.log('doSomethingAsync complete');
});
Copy after login

Node.js 8.0 provides a util.promisify() utility for converting callback-based functions into Promise-based alternatives. There are two conditions:

  • The callback must be passed as the last parameter to the asynchronous function
  • The callback function must expect an error parameter, followed by a value parameter

Example:

async1((err, res) => {
  if (!err) async2(res, (err, res) => {
    if (!err) async3(res, (err, res) => {
      console.log('async1, async2, async3 complete.');
    });
  });
});
Copy after login

Async chain call

Anything that returns a Promise can initiate a series of asynchronous function calls defined in the .then() method. Each function receives the result from the previous resolve:

const db = require('database');

// 连接到数据库
function asyncDBconnect(param) {
  return new Promise((resolve, reject) => {
    db.connect(param, (err, connection) => {
      if (err) reject(err);
      else resolve(connection);
    });
  });
}
Copy after login
The

sync function can also be executed in the .then() block. The return value is passed to the next .then() (if any).

The

.catch() method defines a function that is called when any previous reject is triggered. At this time, no .then() methods will be run again. You can use multiple .catch() methods throughout the chain to catch different errors.

ES2018 introduces a .finally() method that runs any final logic regardless of the result—for example, cleaning up, closing database connections, and more. It is supported in all modern browsers:

result1 = doSomething1();
result2 = doSomething2(result1);
Copy after login
Copy after login
Copy after login

The future of Promise?

Promise reduces callback hell, but also brings its own problems.

Tutorials often do not mention that the entire Promise chain is asynchronous. Any function that uses a series of promises should return its own promise, or run the callback function in the final , .then() or .catch() methods. .finally()

Promise's syntax is usually more complicated than callback functions, with many error-prone places, and debugging can also be troublesome. However, learning the basics is crucial.

You can read more about Promise:

Overview of JavaScript Promise

async/await

Promise can be daunting, so ES2017 introduces async and await. While it may be just syntactic sugar, it makes Promise easier to use and you can avoid the

chain altogether. Consider the following Promise-based example: .then()

doSomethingAsync(callback1);
console.log('finished');

// 当doSomethingAsync完成时调用
function callback1(error) {
  if (!error) console.log('doSomethingAsync complete');
}
Copy after login
Copy after login
Copy after login
To rewrite this code using async/await:

    External functions must start with an async statement
  • Calls to asynchronous, Promise-based functions must start with await to ensure that processing is completed before executing the next command
<code>finished
doSomethingAsync complete</code>
Copy after login
Copy after login
await effectively makes each call look synchronous without taking up single-threaded processing in JavaScript. Furthermore, async functions always return a promise, so they can in turn be called by other async functions.

async/await code may not be shorter, but there are many benefits:

    The syntax is clearer. There are fewer brackets and less likely to make mistakes.
  • Debugging is easier. Breakpoints can be set on any await statement.
  • Error handling is better. You can use the try/catch block just like synchronous code.
  • Good support. It is implemented in all modern browsers and in Node 7.6.
In other words, not everything is perfect...

Upgrade of Promise

async/await depends on the Promise, which ultimately depends on the callback function. This means you still need to understand how Promise works.

In addition, when multiple asynchronous operations are processed, there is no direct equivalent of Promise.all or Promise.race. It's easy to forget Promise.all, which is more efficient than using a series of irrelevant await commands.

Limitations of try/catch

If you omit any try/catch around await that fails, the async function will exit silently. If you have a long list of asynchronous await commands, you may need multiple try/catch blocks.

One alternative is a higher-order function, which catches errors, making the try/catch block unnecessary (thanks to @wesbos for suggestions).

However, this option may not be practical if the application must react to some errors in a different way than other errors.

Despite some shortcomings, async/await is an elegant addition to JavaScript.

You can read more about using async/await: JavaScript async/await Getting Started Guide with Examples

JavaScript Asynchronous Programming Journey

In JavaScript, asynchronous programming is an inevitable challenge. Callback functions are essential in most applications, but they are easy to get stuck in deeply nested functions.

Promise abstracts the callback function, but there are many syntax traps. Converting existing functions can be a chore, and the .then() chain still looks messy.

Luckily, async/await brings clarity. The code looks synchronous, but it cannot be processed exclusively by a single thread. It will change the way you write JavaScript and may even make you appreciate Promise – if you haven’t before!

(The same FAQ part as the original FAQs should be added here)

Please note that I have tried my best to rewrite the text as per your requirements and retain the original format and location of the image. Since I don't have the ability to access external links, I can't verify the validity of the image links, nor can I add the links you requested. Please check and add the necessary links yourself.

The above is the detailed content of Flow Control in JavaScript: Callbacks, Promises, async/await. For more information, please follow other related articles on the PHP Chinese website!

Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Latest Articles by Author
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template