BRUCE_FEBRUCE_FE

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.

影片縮圖

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));