3 ms·
While the idea is correct, the proposed solution is needlessly verbose. A better solution would be to async function getPeople() { const [members, nonMem
by Etheryte 6y ago
While the idea is correct, the proposed solution is needlessly verbose. A better solution would be to
async function getPeople() {
const [members, nonMembers] = await Promise.all([
fetch("/members"),
fetch("/non-members"),
]);
return members.concat(nonMembers);
}
The gist of the article is very true though. This is something that comes up every now and then in code review, even with seasoned developers. I'm not entirely sure what the solution would be since depending on the context, both sequential and parallel execution can be correct. It might just be one of those rite of passage type of mistakes you have to make once or twice.
- jakear 6y agoOr if your env supports Array#flat, const getPeople = async () => (await Promise.all(...)).flat()
- bryanlarsen 6y agoor async function getPeople() { const membersPromise=fetch("/members"); const nonmembersPromise=fetch("/non-members"); return [].concat(await membersPromise, await nonmembersPromise); } edited to fix typo spotted by lhorie. thanks.
- d1plo1d 6y agoI expect that will execute sequentially though as opposed to the solution above it.
- jakear 6y agoNo, the second fetch is spawned before the first awaited. So by the time execution gets deferred both fetches are running.
- kesor 6y agothe execution starts when the function is called - not when "await" is prepended to its result.
- dllthomas 6y agoArguably correct but possibly misleading. The asynchronous portion of the work is enqueued when the function is called, but does not start executing until it's scheduled, which can't happen until the current task ends or is blocked by an await. This is useful, as it means a promise can't settle before you've had a chance to add handlers; otherwise you might sometimes get UnhandledPromiseRejections because of an unavoidable race condition. I said arguably correct because there's nothing stopping the function from doing a portion of the work synchronously, which would mean the work as a whole starts with the function call.
- TheNorthman 6y agoJudging from your comment history, are you perhaps used to writing asynchronous code in Rust? In most languages, `Futures` start executing from when they are spawned. This is opposed to Rust, where they execute when they are `.await`ed.
- deleted 6y ago[deleted]
- d1plo1d 6y agoOk, 3rd edit. The promises are awaited in sequence but since they are both started before the first await they are run in parallel. Your question about Rust futures makes a ton more sense now. This only works because a promise is self-executing / not inert like a Rust Future. Thank you kind stranger! Your async-foo is strong ^_^
- dllthomas 6y agoI don't expect so. IIUC, work to be done for a promise is (typically) placed in the task queue when the promise is created, and will be eligible to start running the next time you get back to the event loop, which is part of what an `await` does.
- lhorie 6y agoThat would throw `Uncaught ReferenceError: members is not defined`. I think you meant `[].concat`
- lhorie 6y agoAm I the only one getting itchy fingers from the lack of normalization? This: async function getPeople() { return fetch('/people') } just seems far more straightforward across the entire stack (where each entry has a `member: boolean` or `type: someEnum` field)
- faizshah 6y agoI agree the example given is poor and as others have pointed out presents a race condition where a DB transaction would be better. I like the introduction to async/await from PouchDB blog: https://pouchdb.com/2015/03/05/taming-the-async-beast-with-es7.html https://pouchdb.com/2015/03/05/taming-the-async-beast-with-e... And their discussion of Promises: https://pouchdb.com/2015/05/18/we-have-a-problem-with-promises.html https://pouchdb.com/2015/05/18/we-have-a-problem-with-promis...