bugfix> javascript > 投稿

複数の時間のかかる関数があり、それらがすべて完了した後に関数を実行したい、例えば:

data.x = thisTakes2Seconds();
data.y = thisTakes5Seconds();
http.post(data);

私はJavascriptのコールバックの概念に精通していますが、私がいくつかの機能を持っている場合、私は本当にいくつかの機能をネストしたコールバックを持っているはずですか?

回答 3 件
  • 非同期関数を簡単に処理するための最良の方法は、 promises を使用することです 、および async/await

    function thisTakes2Seconds() {
      return new Promise(resolve => setTimeout(() => resolve(3), 200)); // 0.2 to avoid waiting :P
    }
    function thisTakes5Seconds() {
      return new Promise(resolve => setTimeout(() => resolve(5), 500));
    }
    async function foo() {
      const data = {};
      
      data.x = await thisTakes2Seconds();
      data.y = await thisTakes5Seconds();
      
      // This will run once both promises have been resolved
      console.log(data);
    }
    foo()
      .then(() => console.log('done!')
      .catch(err => console.error(err));
    
    

    両方の機能を並行して実行したい場合は、そうすることができ、Promise.allの使用が終了するのを待ちます。

    async function foo() {
      const data = {};
      // Promise.all returns an array where each item is the resolved
      // value of the promises passed to it, maintaining the order
      // So we use destructuring to assign those values
      [data.x, data.y] = await Promise.all([
        thisTakes2Seconds(),
        thisTakes5Seconds()
      ]);
      console.log(data);
    }
    
    

    コールバックを使用する非同期関数が既にある場合、簡単に約束に変換できます。

    function myAsyncFunction(callback) {
        setTimeout(() => {
            callback(Math.random());
        }, 200);
    }
    function myAsyncFunctionPromise() {
         return new Promise((resolve, reject) => {
             myAsyncFunction(resolve);
             // If there is an error callback, just pass reject too.
         });
    }
    
    

    bluebirdのようなライブラリには、コールバックAPIを約束するユーティリティメソッドが既にあります。

    http://bluebirdjs.com/docs/api/promise.promisify.html


    ブラウザで実行していて、古いものをサポートする必要がある場合は、babelを使用して async/await を変換できます。  ES5へ

  • あなたの thisTakesXSeconds  関数はすぐに結果を返します。これは、それらが同期的であることを示しています。コールバックの必要はありません。そのコードの実行には約7秒かかります。


    もし  thisTakesXSeconds  始めました非同期 X秒かかったプロセス(ただし、帰る 結果はそうでないことを示唆しています)、完了プロセスを管理する方法を検討します。

    am I really supposed to have nested callbacks several functions deep?

    その質問と、「はい」という答えに対する一般的な不満が、今や私たちに約束があり、さらには async さえもある理由です。  関数。 :-)

    あなたはあなたの thisTakesXSeconds を作ります  関数はプロミスを返し、関数が並行して実行できる場合、これらの行に沿って何かを実行します。

    Promise.all([
        thisTakes2Seconds(),
        thisTakes5Seconds()
    ])
    .then(([x, y]) => {
        data.x = x;
        data.y = y;
        // use or return `data` here
    })
    // return the promise or add a `catch` handler
    
    

    連続して(次々に)実行する必要がある場合、

    thisTakes2Seconds()
        .then(x => {
            data.x = x;
            return thisTakes5Seconds();
        })
        .then(y => {
            data.y = y;
            // use or return `data` here
        })
        // return the promise or add a `catch` handler
    
    

    ...これは async で少し明確に見える  関数:

    data.x = await thisTakes2Seconds();
    data.y = await thisTakes5Seconds();
    // use or return `data` here
    // add appropriate error handling (at this level or when calling the function)
    
    

  • いくつかの非同期呼び出しが実行された後、いくつかのコードの実行を処理するために使用したテクニックの1つは、「完了した」カウンターまたはオブジェクトを使用することです。

    各関数は、以下を含むコールバックを実行します

    if (counter == numberOfFuntionsIWantedToComplete) 
        doTheAfterWeHaveAllDataThing`
    
    

あなたの答え