阿里云主机折上折
  • 微信号
Current Site:Index > Serial and parallel execution

Serial and parallel execution

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

ECMAScript 6 Serial Execution

ECMAScript 6 introduced several mechanisms to handle serial execution, the most important of which are Promises and async/await. Serial execution refers to tasks being executed one after another in sequence, where the next task starts only after the previous one has completed.

Promise Chaining

The then method of Promises can be chained to achieve serial execution:

function task1() {
  return new Promise(resolve => {
    setTimeout(() => {
      console.log('Task 1 completed');
      resolve(1);
    }, 1000);
  });
}

function task2(value) {
  return new Promise(resolve => {
    setTimeout(() => {
      console.log('Task 2 completed, received value:', value);
      resolve(value + 1);
    }, 500);
  });
}

task1()
  .then(task2)
  .then(result => {
    console.log('Final result:', result);
  });

async/await Syntax

async/await makes serial code more intuitive:

async function serialExecution() {
  const result1 = await task1();
  const result2 = await task2(result1);
  console.log('Final result:', result2);
}

serialExecution();

ECMAScript 6 Parallel Execution

Parallel execution refers to launching multiple tasks simultaneously without waiting for the previous task to complete. ECMAScript 6 provides several ways to achieve parallel execution.

Promise.all

Promise.all can execute multiple Promises in parallel and return an array of results once all Promises are completed:

function fetchUser(id) {
  return new Promise(resolve => {
    setTimeout(() => resolve({ id, name: `User${id}` }), Math.random() * 1000);
  });
}

Promise.all([fetchUser(1), fetchUser(2), fetchUser(3)])
  .then(users => {
    console.log('All user data:', users);
  });

Promise.race

Promise.race returns the result of the first completed Promise:

function timeout(ms) {
  return new Promise((_, reject) => {
    setTimeout(() => reject(new Error('Timeout')), ms);
  });
}

Promise.race([fetchUser(1), timeout(500)])
  .then(user => console.log('Fetched user:', user))
  .catch(err => console.error('Error:', err.message));

Combining Serial and Parallel Execution

In real-world development, it's common to mix serial and parallel execution:

async function complexExecution() {
  // Fetch basic information in parallel
  const [user, posts] = await Promise.all([
    fetchUser(1),
    fetchPosts(1)
  ]);
  
  // Process dependent data serially
  const comments = await fetchComments(posts[0].id);
  
  return { user, posts, comments };
}

complexExecution().then(data => console.log(data));

Error Handling Strategies

Different execution methods require different error handling approaches:

Serial Error Handling

async function serialWithErrorHandling() {
  try {
    const result1 = await mightFail();
    const result2 = await anotherTask(result1);
    return result2;
  } catch (error) {
    console.error('Execution failed:', error);
    throw error; // Optionally rethrow or handle
  }
}

Parallel Error Handling

Promise.all([
  task1().catch(err => ({ error: err })),
  task2().catch(err => ({ error: err }))
])
.then(results => {
  const errors = results.filter(r => r.error);
  if (errors.length) {
    console.error('Some tasks failed:', errors);
  }
  return results;
});

Performance Considerations

Parallel execution can significantly improve performance, but the following should be noted:

  1. Browser parallel request limits (typically 6)
  2. Memory consumption
  3. CPU-intensive tasks may block the main thread
// Execute in parallel batches
async function batchParallel(tasks, batchSize = 5) {
  const results = [];
  for (let i = 0; i < tasks.length; i += batchSize) {
    const batch = tasks.slice(i, i + batchSize);
    const batchResults = await Promise.all(batch.map(task => task()));
    results.push(...batchResults);
  }
  return results;
}

Advanced Patterns

Cancelable Promises

function cancellablePromise(promise) {
  let cancel;
  const wrappedPromise = new Promise((resolve, reject) => {
    cancel = () => reject(new Error('Cancelled'));
    promise.then(resolve, reject);
  });
  return { promise: wrappedPromise, cancel };
}

const { promise, cancel } = cancellablePromise(fetchUser(1));
setTimeout(cancel, 500); // Cancel after 500ms

Progress-aware Promises

function progressPromise(executor) {
  const handlers = [];
  const promise = new Promise((resolve, reject) => {
    executor(
      value => resolve(value),
      reason => reject(reason),
      progress => handlers.forEach(h => h(progress))
    );
  });
  
  promise.onProgress = handler => {
    handlers.push(handler);
    return promise;
  };
  
  return promise;
}

const pp = progressPromise((resolve, reject, progress) => {
  let p = 0;
  const interval = setInterval(() => {
    p += 10;
    progress(p);
    if (p >= 100) {
      clearInterval(interval);
      resolve('Completed');
    }
  }, 200);
});

pp.onProgress(p => console.log(`Progress: ${p}%`));

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

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

上一篇:错误处理模式

下一篇:async函数返回值

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 ☕.