I'm mapping over an array and for one of the return values of the new object, I need to make an asynchronous call.
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 } });
The implementation of that function will look something like
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'); } }); }
I'm not clear what's the best approach to do this... promises? Nested callbacks? Use something in ES6 or ES7 and then transpile with Babel?
What's the current best way to implement this?
If you use the async await function and console out the output, then you will find the arrays of promises that are still needed to be resolved. The map doesn't resolve the promises on its own but left the stuff for the developer to resolve. So, that means you can't use async-await in the map.
Inside an async function, you can use the await keyword before a call to a function that returns a promise. This makes the code wait at that point until the promise is settled, at which point the fulfilled value of the promise is treated as a return value, or the rejected value is thrown.
The . map() algorithm applies an async callback to each element of an array, creating promises as it does. However, the returned result by . map() is no promise, but an array of promises.
A Array. map() is a very useful function but, unfortunately, it only works with synchronous functions. A simple workaround for using async map functions is to use Promose.
update in 2018: Promise.all
async function within map callback is easier to implement:
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
: I put the general example for everyone:
Edit@2019/06/19
: async/await should have try/catch to handle error: it would throw a warning message if error occur;
let data = await Promise.all(data.map(async (item) => { try { item.fetchItem = await fetchFunc(item.fetchParams); return item; } catch(err) { throw err; } }));
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With