EN/CH Mode
BRUCE_FE JS Interview Notes - Implement Async Task Execution
Learn how to implement async task execution in JavaScript, master batch processing, concurrency control, execution order management techniques, and enhance frontend capabilities for handling complex workflows.
EN/CH Mode
Lazy to read articles? Then watch videos!
Async Task Execution Overview
In frontend development, we often need to handle multiple asynchronous operations such as API requests, file reading, etc. Effectively managing the execution order, concurrency, and error handling of these async tasks is a common interview topic.
Common Scenarios for Async Task Execution
- 1. Sequential execution: Execute tasks one after another in order
- 2. Parallel execution: Execute multiple tasks simultaneously
- 3. Concurrency control: Limit the number of tasks executing simultaneously
- 4. Task scheduling: Arrange task execution order based on priority or dependencies
- 5. Batch processing: Execute multiple tasks in batches
Basic Sequential Async Task Execution
Sequential execution is the simplest way to execute async tasks, ensuring tasks are executed one after another in the specified order. Below is a basic implementation:
async function executeAsyncTasks(tasks) {
if (tasks.length === 0) {
return;
}
const task = tasks.shift();
const result = await task();
console.log(result);
await executeAsyncTasks(tasks);
}
// 使用範例
const tasks = [
() => Promise.resolve('Task 1 completed'),
() => Promise.resolve('Task 2 completed'),
() => Promise.resolve('Task 3 completed')
];
executeAsyncTasks([...tasks]);
// 依次輸出:
// Task 1 completed
// Task 2 completed
// Task 3 completed
This implementation uses recursion to execute tasks one after another. Each time it executes one task, waits for it to complete, then executes the next task.
Improved Version of Basic Implementation
async function executeAsyncTasks(tasks) {
const results = [];
for (const task of tasks) {
try {
const result = await task();
results.push(result);
} catch (error) {
results.push({ error });
}
}
return results;
}
// 使用範例
const tasks = [
() => Promise.resolve('Success 1'),
() => Promise.reject(new Error('Failed')),
() => Promise.resolve('Success 3')
];
executeAsyncTasks(tasks)
.then(results => console.log(results))
.catch(error => console.error(error));
// 輸出: ['Success 1', { error: Error('Failed') }, 'Success 3']
This improved version collects results from all tasks and handles potential errors, making the entire process more robust.
Practical Application Scenarios
Below are two practical application examples of async task execution:
1. Batch File Upload
async function uploadFiles(files, concurrency = 3) {
const uploadFile = async (file) => {
// Create form data
const formData = new FormData();
formData.append('file', file);
// Simulate upload process
const response = await fetch('/api/upload', {
method: 'POST',
body: formData
});
return await response.json();
};
// Create all upload tasks
const uploadTasks = files.map(file => () => uploadFile(file));
// Use concurrency control for upload
return executeAsyncTasks(uploadTasks);
}
// Usage example
const fileList = [file1, file2, file3];
uploadFiles(fileList)
.then(results => console.log('Upload complete:', results))
.catch(error => console.error('Upload failed:', error));
2. API Data Dependency Processing
async function fetchUserData(userId) {
// Step 1: Get user basic information
const userInfo = await fetch(`/api/user/${userId}`)
.then(res => res.json());
// Step 2: Get related data based on user information
const tasks = [
() => fetch(`/api/posts?userId=${userId}`).then(res => res.json()),
() => fetch(`/api/followers?userId=${userId}`).then(res => res.json())
];
// Execute tasks sequentially
const [posts, followers] = await executeAsyncTasks(tasks);
// Return integrated data
return {
user: userInfo,
posts,
followers
};
}
// Usage example
fetchUserData('user123')
.then(data => {
displayUserProfile(data.user);
displayUserPosts(data.posts);
displayFollowers(data.followers);
})
.catch(error => console.error('Failed to fetch user data:', error));