2017-08-29 8 views
0

戻り値の配列と値の配列を作成しています。一部の値はコールバックで計算されます。しかし、私はプログラムを非同期にする方法を知らないので、すべての結果は配列にあり、返された後は追加されません。戻り値の前に非同期コールバックから配列を作成するNodeJS

let array = [] 
for (stuff : stuffs) { 
    if (condition) { 
    array.add(stuff) 
    } else { 
    api.compute(stuff, callback(resp) { 
      array.add(resp.stuff) 
    } 
    } 
} 
res.json({ "stuff": array }) 

この例では、配列は非同期呼び出しが完了する前に応答に書き込まれます。

どうすれば非同期で動作させることができますか?あなたはのいずれかの方法を使用する必要が

答えて

1

  • 非同期ライブラリー
  • Promise.all
  • コルーチン/ジェネレータ
  • 非同期/

最もクールなまだを待ちます私は、async/awaitだと思います。まず、あなたの関数を変更し、それは約束を返します。

const compute = function(stuff) { 
    return new Promise((resolve, reject) => { 
    api.compute(stuff, callback(resp){ 
     resolve(resp.stuff) 
    }); 
    }); 
}; 

はその後、我々は、非同期ハンドラを使用して、ルートを変更します。

app.get('/', async function(req, res, next) { 
    const array = []; 
    for (const stuff of stuffs) { 
    if (condition) { 
     array.add(stuff); 
    } else { 
     const stuff = await compute(stuff); 
     array.push(stuff); 
    } 
    } 
    res.json({ stuff: array }); 
}); 

注:あなたが最新にノードのバージョンを更新する必要があるかもしれませんが。

UPDATE:イベントループの作品は、このスニペットを実行し、それに仕上げる方法

awaredされていない方は、:

const sleep = async function(ms) { 
    console.log(`Sleeping ${ms}ms`); 
    return new Promise(resolve => setTimeout(resolve, ms)); 
}; 

async function job() { 
    console.log('start'); 

    for (let t = 0; t < 10; t++) { 
    await sleep(100); 
    } 
} 

job(); 

console.log('oops did not expect that oO'); 

あなたは驚かれることでしょう。ここで

+1

これはループに非同期コードを置くために悪い習慣です。むしろpromiseの配列を作成し、次にそれらの 'Promise.all'を作成するべきです。 (非同期が素晴らしいことに同意してください!) –

+0

それは滝と同じですが、それには何が悪いですか? – Lazyexpert

+0

私は@GrégoryNEUTに同意します。非同期コードで作業するときはループを避けるべきです。 –

1

は、コールバック

すべて詰め込むの治療再帰的つもりだ関数を作成を使用してパッケージのない答えです。

getArray(stuffs, callback, index = 0, array = []) { 
    // Did we treat all stuffs? 
    if (stuffs.length >= index) { 
    return callback(array); 
    } 

    // Treat one stuff 
    if (condition) { 
    array.add(stuffs[index]); 

    // Call next 
    return getArray(stuffs, callback, index + 1, array); 
    } 

    // Get a stuff asynchronously 
    return api.compute(stuffs[index], (resp) => { 
    array.add(resp.stuff); 

    // Call next 
    return getArray(stuffs, callback, index + 1, array); 
    }); 
} 

どのようにそれを呼び出すには?

getArray(stuffs, (array) => { 
    // Here you have your array 
    // ... 
}); 

EDIT:より詳細な説明


私たちは、あなたが非同期関数呼び出しを処理ループに持っていたループを変換するために何をしたいのか。

getArrayのコールは、stuffs配列の1つのインデックスを処理することを目的としています。

1つのインデックスを処理した後、関数はすべてが処理されるまで、次のインデックスを処理するために自身を再度呼び出します。

-> Treat index 0 -> Treat index 1 -> Treat index 2 -> Return all result 

私たちは、プロセスを通じて情報を渡すためにパラメータを使用しています。 Index私たちが処理しなければならない配列部分を知るために、そしてarrayは、私たちが計算したものを維持するために使用します。


EDIT:改善への100%非同期soluce我々がここで行っている、それは非同期コードにループのためのあなたの初期のシンプルな転置何


。それはそれを完全に非同期にすることによって改善することができますが、それはより良いが少し難しくなります。例えば

// Where we store the results 
const array = []; 

const calculationIsDone = (array) => { 
    // Here our calculation is done 
    // --- 
}; 

// Function that's gonna aggregate the results coming asynchronously 
// When we did gather all results, we call a function 
const gatherCalculResult = (newResult) => { 
    array.push(newResult); 

    if (array.length === stuffs.length) { 
    callback(array); 
    } 
}; 

// Function that makes the calculation for one stuff 
const makeCalculation = (oneStuff) => { 
    if (condition) { 
    return gatherCalculResult(oneStuff); 
    } 

    // Get a stuff asynchronously 
    return api.compute(oneStuff, (resp) => { 
    gatherCalculResult(resp.stuff); 
    }); 
}; 

// We trigger all calculation 
stuffs.forEach(x => x.makeCalculation(x)); 
+0

これの背後にある考え方を説明できますか?最後のリターンブロックのために機能しますか?なぜ別の方法でブロックしてみませんか? – aclokay

関連する問題