async for loop em node.js

Eu sou novo para este node.js .. Estou um pouco confuso sobre este retorno de chamada..No meu aplicativo dentro de um loop for estou chamando uma chamada de function assíncrona, eu acho que o meu problema é que antes estou recebendo resposta de chamada assíncrona meu for loop obter loop.

Meu código:

async.forEach(Object.keys(config), function(key, next) { search(config[key].query, function(err, result) { // console.log("fffffffffff="+ util.inspect(result))-------- >>>Getting undefined.. if (err) return next(err) // var json = JSON.stringify({ "result": result }); results[key] = { "result": result } console.log("rrrrrrrr="+util.inspect(results[key])) next() // <---- critical piece. This is how the forEach knows to continue to the next loop. Must be called inside search's callback so that it doesn't loop prematurely. }) }, function(err) { console.log('iterating done'); res.writeHead(200, { 'content-type': 'application/json' }); res.end(JSON.stringify(results)); }); } 

Código da function de pesquisa:

 var matches = []; var qrySubString = query.substring(0, 4); client.query("select * from xxxxxxxxx where level4 ILIKE '%" + query + "%'", function(err, row1, fields) { for (var id in row1.rows) { var match, name; if (query == row1.rows[id].level4) { match = true; name = row1.rows[id].level4; } else { match = false; name = query; } matches.push({ "id": id, "name": row1.rows[id].level4, "score": 100, "match": match, "type": [{ "id": "/people/presidents", "name": "US President" }] }) } callback(matches); }) 

Eu quero executar for loop após a execução bem sucedida de 1 function de pesquisa, eu acho que eu tenho que usar async for loop.Por favor me orientar para resolver isso .. Obrigado antecipadamente ..

Reduzi seu exemplo de código para as linhas a seguir para facilitar a compreensão da explicação do conceito.

 var results = []; var config = JSON.parse(queries); for (var key in config) { var query = config[key].query; search(query, function(result) { results.push(result); }); } res.writeHead( ... ); res.end(results); 

O problema com o código anterior é que a function de search é assíncrona, portanto, quando o loop tiver terminado, nenhuma das funções de retorno de chamada foi chamada. Consequentemente, a lista de results está vazia.

Para corrigir o problema, você precisa colocar o código após o loop na function de retorno de chamada.

  search(query, function(result) { results.push(result); // Put res.writeHead( ... ) and res.end(results) here }); 

No entanto, como a function de retorno de chamada é chamada várias vezes (uma vez para cada iteração), você precisa saber de alguma forma que todos os retornos de chamada foram chamados. Para fazer isso, você precisa contar o número de retornos de chamada e verificar se o número é igual ao número de chamadas de function assíncrona.

Para obter uma lista de todas as chaves, use Object.keys . Então, para percorrer essa lista, eu uso .forEach (você também pode usar for (var i = 0, key = keys[i]; i < keys.length; ++i) { .. } , mas isso poderia dar problemas, veja o fechamento do JavaScript dentro de loops - exemplo prático simples ).

Aqui está um exemplo completo:

 var results = []; var config = JSON.parse(queries); var onComplete = function() { res.writeHead( ... ); res.end(results); }; var keys = Object.keys(config); var tasksToGo = keys.length; if (tasksToGo === 0) { onComplete(); } else { // There is at least one element, so the callback will be called. keys.forEach(function(key) { var query = config[key].query; search(query, function(result) { results.push(result); if (--tasksToGo === 0) { // No tasks left, good to go onComplete(); } }); }); } 

Nota: O código asynchronous no exemplo anterior é executado em paralelo. Se as funções precisarem ser chamadas em uma ordem específica, você poderá usar a recursion para obter o efeito desejado:

 var results = []; var config = JSON.parse(queries); var keys = Object.keys(config); (function next(index) { if (index === keys.length) { // No items left res.writeHead( ... ); res.end(results); return; } var key = keys[index]; var query = config[key].query; search(query, function(result) { results.push(result); next(index + 1); }); })(0); 

O que eu mostrei são os conceitos, você poderia usar um dos muitos módulos NodeJS (de terceiros) em sua implementação, como async .

Você diagnosticou corretamente seu problema, tão bom trabalho. Uma vez que você chama seu código de busca, o loop for continua em frente.

Eu sou um grande fã de https://github.com/caolan/async , e isso me serve bem. Basicamente, você acabaria com algo como:

 var async = require('async') async.eachSeries(Object.keys(config), function (key, next){ search(config[key].query, function(err, result) { // <----- I added an err here if (err) return next(err) // <---- don't keep going if there was an error var json = JSON.stringify({ "result": result }); results[key] = { "result": result } next() /* <---- critical piece. This is how the forEach knows to continue to the next loop. Must be called inside search's callback so that it doesn't loop prematurely.*/ }) }, function(err) { console.log('iterating done'); }); 

Espero que isso ajude!

Eu gosto de usar o padrão recursivo para esse cenário. Por exemplo, algo como isto:

 // If config is an array of queries var config = JSON.parse(queries.querrryArray); // Array of results var results; processQueries(config); function processQueries(queries) { var searchQuery; if (queries.length == 0) { // All queries complete res.writeHead(200, {'content-type': 'application/json'}); res.end(JSON.stringify({results: results})); return; } searchQuery = queries.pop(); search(searchQuery, function(result) { results.push(JSON.stringify({result: result}); processQueries(); }); } 

processQueries é uma function recursiva que processQueries um elemento de consulta de uma matriz de consultas para processar. Em seguida, a function de retorno de chamada chama processQueries novamente quando a consulta é concluída. O processQueries sabe terminar quando não há mais consultas.

É mais fácil fazer isso usando arrays, mas ele pode ser modificado para funcionar com valores / chave de object, imagino.

Node.js introduzido async await em 7.6 que torna o Javascript mais bonito.

 var results = []; var config = JSON.parse(queries); for (var key in config) { var query = config[key].query; results.push(await search(query)); } res.writeHead( ... ); res.end(results); 

Para isso, a function de search tem que retornar uma promise ou tem que ser function async

Se não está retornando uma Promise você pode ajudá-la a retornar uma Promise

 function asyncSearch(query) { return new Promise((resolve, reject) => { search(query,(result)=>{ resolve(result); }) }) } 

Em seguida, substitua esta linha await search(query); por await asyncSearch(query);