阿里云主机折上折
  • 微信号
Current Site:Index > The syntax of async functions

The syntax of async functions

Author:Chuan Chen 阅读数:4217人阅读 分类: JavaScript

ECMAScript 6 introduced the async/await syntax, revolutionizing the way asynchronous programming is handled in JavaScript. Built on Promises, it provides a more intuitive synchronous coding style for handling asynchronous operations, significantly improving code readability and maintainability.

Basic Syntax of async Functions

An async function is defined by adding the async keyword before the function declaration. Regardless of the return value, it always returns a Promise:

async function fetchData() {
  return 'data';
}

// Equivalent to
function fetchData() {
  return Promise.resolve('data');
}

When an error is thrown inside the function, it is automatically converted into a rejected Promise:

async function fail() {
  throw new Error('Failed');
}

fail().catch(err => console.log(err)); // Catch the error

How the await Expression Works

The await keyword can only be used inside an async function. It pauses the function execution until the Promise is resolved:

async function getUser() {
  const response = await fetch('/api/user');
  const data = await response.json();
  return data;
}

When encountering a non-Promise value, await directly returns the value:

async function foo() {
  const result = await 42; // Equivalent to Promise.resolve(42)
  console.log(result); // 42
}

Error Handling Mechanism

Traditional try/catch structures can be used inside async functions to handle errors:

async function loadData() {
  try {
    const res = await fetch('invalid-url');
    return await res.json();
  } catch (err) {
    console.error('Fetch failed:', err);
    throw err; // Can continue to propagate the error
  }
}

Alternatively, errors can be handled using the Promise's catch method:

loadData()
  .then(data => console.log(data))
  .catch(err => console.error('External handling:', err));

Optimizing Parallel Execution

Multiple independent asynchronous operations can be executed in parallel as follows:

async function parallel() {
  const [user, posts] = await Promise.all([
    fetch('/user'),
    fetch('/posts')
  ]);
  
  return {
    user: await user.json(),
    posts: await posts.json()
  };
}

Usage in Class Methods

async can also be used in class methods:

class ApiClient {
  async getResource(url) {
    const response = await fetch(url);
    return response.json();
  }
}

const client = new ApiClient();
client.getResource('/users').then(console.log);

Application in Arrow Functions

Arrow functions also support the async syntax:

const fetchUser = async (id) => {
  const res = await fetch(`/users/${id}`);
  return res.json();
};

Practical Use Case Example

Implementing a request function with retry logic:

async function fetchWithRetry(url, retries = 3) {
  for (let i = 0; i < retries; i++) {
    try {
      const response = await fetch(url);
      if (!response.ok) throw new Error(response.statusText);
      return await response.json();
    } catch (err) {
      if (i === retries - 1) throw err;
      await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1)));
    }
  }
}

Comparison with Generator Functions

Although generator functions combined with yield can achieve similar results, async/await syntax is more concise:

// Generator approach
function* genFetch() {
  const res = yield fetch('/data');
  const data = yield res.json();
  return data;
}

// async/await approach
async function asyncFetch() {
  const res = await fetch('/data');
  return await res.json();
}

Common Pitfalls and Considerations

  1. await in Loops: Sequential execution of asynchronous operations in loops may cause performance issues.
// Incorrect sequential execution
async function processArray(array) {
  for (const item of array) {
    await processItem(item); // Each waits for the previous to complete
  }
}

// Correct parallel processing
async function processArray(array) {
  await Promise.all(array.map(item => processItem(item)));
}
  1. Top-Level await: Top-level await can be used directly in ES modules but will throw an error in regular scripts.
// Valid in modules
const data = await fetchData();
console.log(data);

// Throws an error in non-module environments
  1. Excessive Nesting in Promise Chains: Although async/await avoids callback hell, misuse can still lead to deep nesting.
// Not recommended: Deep nesting
async function badPractice() {
  const user = await getUser();
  if (user) {
    const profile = await getProfile(user.id);
    if (profile) {
      const posts = await getPosts(profile.id);
      // ...
    }
  }
}

// Improved flat structure
async function betterPractice() {
  const user = await getUser();
  if (!user) return;
  
  const profile = await getProfile(user.id);
  if (!profile) return;
  
  return await getPosts(profile.id);
}

Performance Considerations

Although async/await introduces minor runtime overhead, this difference is negligible in modern JavaScript engines. More importantly, it enhances development efficiency and code maintainability. The V8 engine has specific optimizations for async/await, making its performance comparable to native Promise chains.

本站部分内容来自互联网,一切版权均归源网站或源作者所有。

如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn

上一篇:国际化API

下一篇:await表达式

Front End Chuan

Front End Chuan, Chen Chuan's Code Teahouse 🍵, specializing in exorcising all kinds of stubborn bugs 💻. Daily serving baldness-warning-level development insights 🛠️, with a bonus of one-liners that'll make you laugh for ten years 🐟. Occasionally drops pixel-perfect romance brewed in a coffee cup ☕.