son - promesas javascript
¿La mejor manera de llamar a una función asíncrona dentro del mapa? (5)
2019
advertencia con Promise.all, no se ejecutan en el orden exacto, algunos servidores no pueden admitir consultas de ejecución simultánea o llamadas de API.
Más bibliotecas nuevas hacen que mis aplicaciones de una sola página tengan más de 4 megas construidas. Así que he decidido no agregar más nuevas librerías como lodash, etc., que se pueden reemplazar con código. Me esperan buenas soluciones para usar con el mapa:
rows.map ( ( record ) => {
try {
(async () => {
let col = await client.query(`SELECT * FROM customers`);
})();
} catch (err) {
console.log(err);
}
});
Estoy mapeando sobre una matriz y para uno de los valores de retorno del nuevo objeto, necesito hacer una llamada asincrónica.
var firebaseData = teachers.map(function(teacher) {
return {
name: teacher.title,
description: teacher.body_html,
image: urlToBase64(teacher.summary_html.match(/src="(.*?)"/)[1]),
city: metafieldTeacherData[teacher.id].city,
country: metafieldTeacherData[teacher.id].country,
state: metafieldTeacherData[teacher.id].state,
studioName: metafieldTeacherData[teacher.id].studioName,
studioURL: metafieldTeacherData[teacher.id].studioURL
}
});
La implementación de esa función se verá más o menos como
function urlToBase64(url) {
request.get(url, function (error, response, body) {
if (!error && response.statusCode == 200) {
return "data:" + response.headers["content-type"] + ";base64," + new Buffer(body).toString(''base64'');
}
});
}
No estoy claro cuál es el mejor enfoque para hacer esto ... ¿promesas? Devoluciones de llamada anidadas? ¿Usar algo en ES6 o ES7 y luego transpilar con Babel?
¿Cuál es la mejor forma actual de implementar esto?
¡Gracias!
Estoy usando una función asincrónica sobre la matriz. Y no usando array.map, sino una función for. Es algo como esto:
const resultingProcessedArray = async function getSomeArray() {
try {
let { data } = await axios({url: ''/myUrl'', method:''GET''}); //initial array
let resultingProcessedArray = [];
for (let i = 0, len = data.items.length; i < len; i++) {
let results = await axios({url: `/users?filter=id eq ${data.items[i].someId}`, method:''GET''});
let domainName = results.data.items[0].domainName;
resultingProcessedArray.push(Object.assign(data.items[i], {domainName}));
}
return resultingProcessedArray;
} catch (err) {
console.error("Unable to fetch the data", err);
return [];
}
};
Puede usar async.map .
var async = require(''async'');
async.map(teachers, mapTeacher, function(err, results){
// results is now an array of stats for each file
});
function mapTeacher(teacher, done) {
// computing stuff here...
done(null, teacher);
}
tenga en cuenta que todos los profesores se procesarán en paralelo; también puede usar estas funciones:
mapSeries(arr, iterator, [callback])
asigna uno por uno
mapLimit(arr, limit, iterator, [callback])
asigna un
limit
mapas al mismo tiempo
Un enfoque es
Promise.all
(ES6)
.
Esta respuesta funcionará en el Nodo 4.0+.
Las versiones anteriores necesitarán un polyfill o biblioteca Promise.
También he usado las funciones de flecha ES6, que podría reemplazar con
function
regulares para Nodo <4.
Esta técnica envuelve manualmente
request.get
con una Promesa.
También podría usar una biblioteca como
request-promise
.
function urlToBase64(url) {
return new Promise((resolve, reject) => {
request.get(url, function (error, response, body) {
if (!error && response.statusCode == 200) {
resolve("data:" + response.headers["content-type"] + ";base64," + new Buffer(body).toString(''base64''));
} else {
reject(response);
}
});
})
}
// Map input data to an Array of Promises
let promises = input.map(element => {
return urlToBase64(element.image)
.then(base64 => {
element.base64Data = base64;
return element;
})
});
// Wait for all Promises to complete
Promise.all(promises)
.then(results => {
// Handle results
})
.catch(e => {
console.error(e);
})
actualización en 2018: la función asincrónica
Promise.all
dentro de la devolución de llamada del mapa es más fácil de implementar:
let firebaseData = await Promise.all(teachers.map(async teacher => {
return {
name: teacher.title,
description: teacher.body_html,
image: await urlToBase64(teacher.summary_html.match(/src="(.*?)"/)[1]),
city: metafieldTeacherData[teacher.id].city,
country: metafieldTeacherData[teacher.id].country,
state: metafieldTeacherData[teacher.id].state,
studioName: metafieldTeacherData[teacher.id].studioName,
studioURL: metafieldTeacherData[teacher.id].studioURL
}
}));
async function urlToBase64(url) {
return request.get(url, function (error, response, body) {
if (!error && response.statusCode == 200) {
return "data:" + response.headers["content-type"] + ";base64," + new Buffer(body).toString(''base64'');
}
});
}
Edit @ 2018/04/29: pongo el ejemplo general para todos:
Editar @ 2019/06/19: async / await debería tener try / catch para manejar el error, si no, arrojaría un mensaje de advertencia;
let data = await Promise.all(data.map(async (item) => {
try {
item.fetchItem = await fetchFunc(item.fetchParams);
return item;
} catch(err) {
throw err;
}
});