JavaScript の約束 tl;dr


Promise に関する詳細の超簡単な概要.話をやめて、話を始めましょう.

約束はいつも連鎖する


then または catch が promise ではない値を返した場合、それは新しい promise にラップされ、チェーンされて次のものに転送されます.つまり、catch から開始して値を返すことができ、.then を返すことができます.

ここのサンプルはすべて Hello World1 を出力します

const appendWorld = s => `${s} World`;
const appendOne = s => `${s}1`;
const log = v => console.log(v);

Promise.resolve('Hello').then(appendWorld).then(appendOne).then(log);
Promise.resolve('Hello').then(v => Promise.resolve(appendWorld(v))).then(appendOne).then(log);
Promise.reject('Hello').catch(appendWorld).then(appendOne).then(log);
Promise.resolve('Blogging').then(() => 'Hello').then(appendWorld).then(appendOne).then(log)


最後に


finally 連鎖可能な値を返すことはできません.その名前から暗示されているようなものです.別の .then または .catch が以前に呼び出されたかどうかに関係なく呼び出されます. Promise が何らかの形で達成されると、.finally が呼び出されます.クリーンアップ作業に適しています.

例えば.

Promise.reject()
  .catch(() => console.log('Catch is called'))
  .finally((s) => console.log('finally called'))


出力

Catch is called
finally is called


promise 内のエラーは .catch に転送されます




Promise.resolve()
  .then(() => {})
  .then(() => { throw new Error('hey') })
  .then(() => console.log('i am never called'))
  .catch(() => console.log('error'));


複数の .catch ステートメントが便利です




Promise.resolve()
  .then(() => Promise.reject())
  .catch(() => console.log('much rejection'))
  .then(() => console.log('i can continue doing stuff'))
  .then(() => Promise.reject('another one'))
  .catch(() => console.log('catching the second chain'))


async 関数は Promise ラッパーです



次のコード ステートメントは同じ効果があります.

// async
async function foobar() {
  return 'foo';
}

// non-async
function foobar() {
  return Promise.resolve('foo');
}


約束を待つことは慎重に行わなければならない


await promise の場合、エラーが隠されている可能性があるため、「成功」をチェックするときに注意する必要があります.

次の例を参照してください.

const foobar = await Promise.reject(new Error('error thrown')).catch(error => error);

if (foobar) {
  // This does not imply success ⚠️👩‍🚀
} else {
 // This does not imply an error case
}


問題は、提供された promise が適切にキャッチされていることです. promise-chaining に戻ると、catch ステートメントの結果をチェーンできるため、new Error... を呼び出すと、.then が結果のオブジェクトになります.これは単に await を呼び出すのと同じです.したがって、ここで foobar には new Error... が含まれています.これは、エラーがスローされたにもかかわらず、if(foobar) をチェックすると true を返すオブジェクトです.したがって、約束が何を返すかを認識する必要があります.

Promise.race と Promise.any


raceany はどちらも、最初に Promise を完了します.しかし、大きな違いがあります.race は最初の Promise で解決または拒否のいずれかで終了しますが、any は最初に実際に解決された Promise でのみ終了します.

この Promise.race サンプルでは、​​Promise が最初であるため、Promise が優先されます.

const promise1 = new Promise((resolve, reject) => setTimeout(reject, 100));
const promise2 = new Promise((resolve, reject) => setTimeout(resolve, 300));
Promise
  .race([promise1, promise2])
  .then(v => console.log('resolved', v))
  .catch(v => console.log('error', v));


この Promise.any サンプルでは、​​解決された Promise が実際に最初に解決されるため、優先されます.

const promise1 = new Promise((resolve, reject) => setTimeout(reject, 100));
const promise2 = new Promise((resolve, reject) => setTimeout(resolve, 300));
Promise
  .any([promise1, promise2])
  .then(v => console.log('resolved', v))
  .catch(v => console.log('error', v));


Promise.all



これは非常に直感的です.すべての promise が解決されたときに解決するか、promise の 1 つが拒否されたときに拒否します.

// outputs ['one', 'two']
Promise.all([Promise.resolve('one'), Promise.resolve('two')])
.then((resultArray) => console.log(resultArray))



// outputs 'error'
Promise.all([Promise.resolve('one'), Promise.resolve('two'), Promise.reject()])
.then((resultArray) => console.log(resultArray))
.catch(() => console.log('error'))