Promise

Promise は非同期処理においてコールバック (事後処理/エラー処理) を登録しておき、処理に応じて呼び出す仕組み。メソッドチェーンにより順次処理を連結することができる。

new を使ってコンストラクタを呼び出して Promise オブジェクトを生成する。

new Promise( /* executor */ function (resolve, reject) { ... } )

Promise オブジェクト生成の際に executor 関数は即時に実行される。(Promise コンストラクタがオブジェクトを返すよりも前に executor は実行される。)

executor は通常、非同期な作業の実行が完了した際に resolve 関数 (成功した場合) もしくは reject 関数 (エラーが発生した場合) のいずれか一方を呼び出す。

resolve 関数と reject 関数は呼び出されると Promise に対してそれぞれ「解決 (resolve)」もしくは「拒否/棄却 (reject)」を行う。

executor 関数でエラーが投げられた場合、Promisereject される。

executor の返り値は無視される。(返り値は意味を持たない。)

doSomething()Promise を返す場合に、then 関数を連結して呼び出すことで成功した場合と失敗した場合の2種類のコールバックを指定することができる。

doSomething().then(successCallback, failureCallback)

戻り値の Promise に順次コールバックを追加して、Promise チェーンを記述することができる。(次の処理を then 関数で連結するために各処理で Promise オブジェクトを返す。最終処理は Promise オブジェクトを返す必要はない。)

doSomething()
.then(function (result) {
  return doSomethingElse(result)
})
.then(function (newResult) {
  return doThirdThing(newResult)
})
.then(function (finalResult) {
  console.log('Got the final result: ' + finalResult)
})
.catch(failureCallback)

catch(failureCallback)then(null, failureCallback) のショートハンド。

アロー関数を使って、Promise チェーンを次のように記述できる。

new Promise((resolve, reject) => {
  console.log('Initial')
  resolve()
})
.then(() => {
  throw new Error('Something failed')
  console.log('Do this')
})
.catch(() => {
  console.log('Do that')
})
.then(() => {
  console.log('Do this whatever happened before')
})

// => printed result:
// Initial
// Do that
// Do this whatever happened before

参考:

Promise を使う | MDN

Promise | MDN

Promise による非同期処理の書き方 | 30歳からのプログラミング

Promise について学ぶ – Qiita

Promise と仲良くなって気持ち良く非同期処理を書こう – Qiita

Promise – 非同期処理の完了処理 | SYNCER

JavaScript の Promise: 概要 | Google Developers

JavaScriptプログラミング講座 Promise について | HAKUHIN’s home page

Node.js を使った非同期処理の理解 | Solutionware 開発ブログ

Promise を使った非同期処理 | kakts-log

メソッドチェーン

参考:

Promise のメソッドチェーンの使い方まとめ – Qiita

シンタックスシュガー async / await の使い方

同期バージョン

try {
  let result      = syncDoSomething()
  let newResult   = syncDoSomethingElse(result)
  let finalResult = syncDoThirdThing(newResult)
  console.log(`Got the final result: ${finalResult}`)
} catch(error) {
  failureCallback(error)
}

非同期バージョン

async function foo() {
  try {
    let result      = await doSomething()
    let newResult   = await doSomethingElse(result)
    let finalResult = await doThirdThing(newResult)
    console.log(`Got the final result: ${finalResult}`)
  } catch(error) {
    failureCallback(error)
  }
}

参考:

Promise を使う | MDN

asynchronous – How to wait for a JavaScript Promise to resolve before resuming function? – Stack Overflow

非同期関数の書き方

async function myAsyncFunction() {
  try {
    const fulfilledValue = await promise
  }
  catch (rejectedValue) {
    // error handling
  }
}

関数定義の前に async キーワードを使用すると、その関数内で await を使用できる。 Promiseawait する場合、この関数はブロックすることなく Promise が完了状態になるまで一時停止する。Promise が解決すると値が返される。Promise が棄却すると棄却された値がスローされる。

参考:

非同期関数 – Promise をわかりやすくする | Google Developers

finally / always

参考:

Promise.prototype.finally() | MDN

Execute something regardless of resolve / reject? – Stack Overflow

Promise.all

参考:

Promise と async / await で複数の非同期処理の完了を待機する | abcdefg…..

Promise.all() | MDN

並列処理/直列処理

並列処理

  • Promise.all()

直列処理

  • then() をチェインする
  • Array.prototype.reduce() を使う
  • ジェネレータを使う
  • async / await を使う

reduce を使った直列処理

let itemIDs = [1, 2, 3, 4, 5]

itemIDs.reduce((promise, itemID) => {
  return promise.then(_ => api.deleteItem(itemID))
}, Promise.resolve())

参考:

JavaScript の Promise – Qiita

最近の js 非同期処理 Promise と Generator の共存 – Qiita

Promise を Array#reduce で直列に実行する | 四角革命前夜

Promise を返す関数の直列実行における reduce の利用と注意点 – Qiita

Promise を複数の直列処理と並列処理を組み合わせる – Qiita

Why Using reduce() to Sequentially Resolve Promises Works | CSS-Tricks

ES6 Promises: Patterns and Anti-Patterns | DataFire.io

Resolving Promises Sequentially | Hacker Noon

Serial Promise Execution with JavaScript | derp turkey

Running Promises in Serial with Array.reduce() | Decembersoft Inc.

Resolve promises one after another (i.e. in sequence)? – Stack Overflow

Promise と Callback の両方に対応する関数

参考:

Promise と Callback の両方に対応する関数の書き方 | Tokyo Otaku Mode Blog

Promise.defer / Deferred

***OBSOLATE***

ECMAScript では採用されなかった。使用するにはポリフィル (PromiseDefer.js など) が必要。

参考:

Deferred | MDN

Unhandled Promise Rejection

参考:

Node.js で捕捉されなかった Promise 内の例外をスタックトレースで表示する – Qiita

Promise Error Handling (slide) | azu.github.io

How to prevent your Node.js process from crashing | DailyJS

loud-rejection

参考:

sindresorhus/loud-rejection: Make unhandled promise rejections fail loudly instead of the default silent fail – GitHub

hard-rejection

参考:

sindresorhus/hard-rejection: Make unhandled promise rejections fail hard right away instead of the default silent fail – GitHub

PromiseDefer.js

参考:

moll/js-promise-defer: JavaScript Polyfill for Promise.defer. Uses the native ES6 Promise. Supports other Promises/A+ implementations. – GitHub

promise-defer – npm

Deferred

参考:

medikoo/deferred: Modular and fast Promises implementation for JavaScript – GitHub

deferred – npm

node-promise-retry

非同期処理を失敗時に指定した回数だけリトライする。

参考:

IndigoUnited/node-promise-retry: Retries a function that returns a promise, leveraging the power of the retry module. – GitHub

promise-retry – npm

タグ:

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です