The syntax of async functions
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
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)));
}
- Top-Level
await
: Top-levelawait
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
- 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