Javascript: devolver un valor a una variable fuera de una función de callback

Tengo una pregunta muy específica y espero que alguien pueda echarme una mano aquí. Soy bastante verde cuando se trata de Javascript mucho más cuando se trata de NodeJS.

Estoy utilizando la funcionalidad lodash de _.forIn para recorrer y agregar en un objeto que está dentro de una matriz. Todo parece algo así:

 [ { id: 20, keywords: 'shirts' }, { id: 18, keywords: 'shoes' } ] 

Básicamente es una lista de palabras clave guardadas en db elasticsearch. Estoy tratando de encontrar una manera de agregar a este objeto un contador del número de resultados que obtendrían estas palabras clave.

Este recuento provendrá de una configuración de elasticsearch que utilizamos para buscar en nuestra base de datos de productos.

La salida que me gustaría obtener sería algo como esto:

 [ { id: 20, keywords: 'shirts', count: 4 }, { id: 18, keywords: 'shoes', count: 15 } ] 

Este es el código que tengo ahora:

 function get_list( data ) { var list_data = data; var list = _.forIn( data, function( item, n, list_data ) { get_count( item, function( count_number ) { list_data[n].count = count_number; }) }); console.log( list, list_data ); } function get_count( item, callback ) { var query = { // elasticsearch query here }; // elasticsearch query here, that returns the count in a callback es.count( query, function(count_number) { callback(count_number) } ); } 

Cuando ejecuto esto, la consola mostrará una matriz sin cambios. He comprobado todos los datos devueltos en cada función, todo lo comprueba. Parece que no puedo obtener los datos correctamente en la list ni en la list list_data .

PD. Este no es mi código real, pero es básicamente su esencia, por lo que puede haber algunos errores tipográficos.

Además, list y list_data es el resultado de mi bash de averiguar cómo funciona esto. He intentado leer cómo funcionan las devoluciones de llamada de JS, pero nada de lo que he visto parece poder ayudarme con mi problema.

Puede verificar el objeto list_data solo después de que todas las callbacks hayan finalizado.

Si desea validar que su función get_count está funcionando, puede mover el get_count dentro de la callback , esto resultará en múltiples registros de los list_data en la consola.

 function get_list( data ) { var list_data = data; var list = _.forIn( data, function( item, n, list_data ) { get_count( item, function( count_number ) { list_data[n].count = count_number; console.log( list, list_data ); }) }); } function get_count( item, callback ) { var query = { // elasticsearch query here }; // elasticsearch query here, that returns the count in a callback es.count( query, function(count_number) { callback(count_number) } ); } 

Para hacer esto, recomiendo usar el módulo async con es bastante bueno para manejar llamadas asíncronas como la suya.

Aquí está el enlace del módulo para que pueda comenzar a usarlo: https://github.com/caolan/async

Así es como implementaría el módulo async en nuestro caso:

 var async = require('async'); function get_list(data) { var list_data = data; //Transform all the list_data objects adding the count prop. async.map(list_data, get_count, function(err, results) { console.log(results); }); } function get_count(item, callback) { var query = { // elasticsearch query here }; // elasticsearch query here, that returns the count in a callback es.count(query, function(count_number) { //add the new prop to the item item.count = count_number; //return the transformed object callback(null, item); }); }