JavaScriptの非同期処理Promiseの基礎と使い方

先生

JavaScriptの非同期処理、もう怖くない!Promiseをマスターして、快適な開発ライフを送ろう🚀

JavaScript Promiseとは?非同期処理の基本

JavaScriptにおけるPromiseは、非同期処理をより扱いやすくするためのオブジェクトです。非同期処理とは、時間のかかる処理(例えば、APIリクエストやファイル読み込み)が完了するのを待たずに、次の処理に進むことができる仕組みのことです。

Promiseは、非同期処理の結果(成功または失敗)を保持し、その結果が利用可能になったときに、適切な処理を行うための手段を提供します。

Promiseには3つの状態があります。

1. Pending (保留): 非同期処理がまだ完了していない状態。

2. Fulfilled (成功): 非同期処理が成功し、結果が得られた状態。

3. Rejected (失敗): 非同期処理が失敗した状態。

Promiseの基本的な使い方

Promiseは、new Promise()コンストラクタを使って作成します。コンストラクタには、resolverejectという2つの関数を引数として持つ関数を渡します。

const promise = new Promise((resolve, reject) => {
  // 非同期処理
  setTimeout(() => {
    const success = true; // 例:処理の成功/失敗
    if (success) {
      resolve('処理成功!'); // 成功した場合、resolveを呼び出す
    } else {
      reject('処理失敗...'); // 失敗した場合、rejectを呼び出す
    }
  }, 1000); // 1秒後に実行
});

resolve()はPromiseを成功状態にし、reject()はPromiseを失敗状態にします。

Promiseの結果を処理するには、.then()メソッドと.catch()メソッドを使用します。

.then()はPromiseが成功した場合に実行される関数を指定します。.catch()はPromiseが失敗した場合に実行される関数を指定します。

promise
  .then((value) => {
    console.log(value); // '処理成功!' が表示される
  })
  .catch((error) => {
    console.error(error); // '処理失敗...' が表示される
  });

Promiseチェーン:非同期処理の連続実行

Promiseチェーンを使用すると、複数の非同期処理を順番に実行することができます。.then()メソッドは、新しいPromiseを返すことができるため、処理を連鎖させることができます。

function asyncTask(value) {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve(value * 2); // 2倍にしてresolve
    }, 500);
  });
}

asyncTask(5)
  .then((result1) => {
    console.log('1回目の結果:', result1); // 10
    return asyncTask(result1); // 10を引数に次の非同期処理
  })
  .then((result2) => {
    console.log('2回目の結果:', result2); // 20
    return asyncTask(result2); // 20を引数に次の非同期処理
  })
  .then((result3) => {
    console.log('3回目の結果:', result3); // 40
  });

この例では、asyncTask関数が非同期処理を模倣しています。.then()メソッドを連鎖させることで、前の処理の結果を次の処理に渡すことができます。

async/await:よりシンプルに非同期処理を記述

async/awaitは、Promiseをより簡潔に記述するためのシンタックスシュガーです。async関数内でawaitキーワードを使用すると、Promiseが完了するまで処理を一時停止し、結果を同期的に取得できます。

async function processData() {
  try {
    const result1 = await asyncTask(5);
    console.log('1回目の結果:', result1);

    const result2 = await asyncTask(result1);
    console.log('2回目の結果:', result2);

    const result3 = await asyncTask(result2);
    console.log('3回目の結果:', result3);

  } catch (error) {
    console.error('エラー:', error);
  }
}

processData();

asyncキーワードは関数の前に記述し、awaitキーワードはPromiseを返す関数の呼び出しの前に記述します。try...catchブロックを使用して、エラーを処理することができます。

async/awaitを使用することで、非同期処理を同期処理のように記述できるため、コードの見通しが良くなります。

Promise.all()とPromise.race()

Promise.all()は、複数のPromiseを並行して実行し、すべてのPromiseが成功するまで待ちます。すべてのPromiseが成功した場合、結果はPromiseの解決値の配列として返されます。いずれかのPromiseが失敗した場合、すぐにエラーが発生します。

const promise1 = Promise.resolve(3);
const promise2 = new Promise((resolve, reject) => setTimeout(resolve, 200, 'foo'));
const promise3 = 42;

Promise.all([promise1, promise2, promise3]).then((values) => {
  console.log(values); // [3, 'foo', 42]
});

Promise.race()は、複数のPromiseを並行して実行し、最初に成功または失敗したPromiseの結果を返します。

const promise1 = new Promise((resolve, reject) => {
    setTimeout(resolve, 500, 'one');
  });
  
  const promise2 = new Promise((resolve, reject) => {
    setTimeout(resolve, 100, 'two');
  });
  
  Promise.race([promise1, promise2]).then((value) => {
    console.log(value);
    // Both resolve, but promise2 is faster
  });
  // Expected output: "two"

参考リンク

まとめ

Promiseは、JavaScriptにおける非同期処理を扱うための強力なツールです。.then().catch()を使用して結果を処理したり、Promiseチェーンで処理を連鎖させたり、async/awaitでよりシンプルに記述したりできます。Promise.all()Promise.race()を使うことで、複数の非同期処理を効率的に扱うことができます。これらの機能を理解し、適切に活用することで、より洗練された非同期処理を実装できるようになります。