This will have examples in a file grouped by topic. These are FAQs from co-workers, etc.
Last active
April 20, 2022 00:42
-
-
Save James-Firth/9a516e2f506c7a76d8577035e7226826 to your computer and use it in GitHub Desktop.
Demonstrates errors handling arrays of promises
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
This is a demo file to show how async/await works when iterating through a list of calls | |
*/ | |
// ===== SETUP AND FAKE API ====== | |
// These functions represent functions that take time to return like API/Network calls | |
function fakeApiCall(message, timeout) { | |
return new Promise((resolve, reject) => { | |
setTimeout(() => { | |
console.log(`\t\t`, new Date(), message); | |
resolve(); | |
}, timeout); | |
}); | |
} | |
const zerothCall = () => { | |
return fakeApiCall('ZERO', 5000); | |
}; | |
const firstCall = () => { | |
return fakeApiCall('ONE', 3000); | |
}; | |
const secondCall = () => { | |
return fakeApiCall('TWO', 1000); | |
}; | |
// Put them in an array so we can call them all | |
const apiCallsToMake = [zerothCall, firstCall, secondCall]; | |
// ====== BROKEN (on purpose) ====== | |
async function doesNotWorkAsIntended() { | |
console.log('=== START OF BAD 1 ==='); | |
// Nothing is causing us to wait for runMe (ie each API call) to complete | |
// so it'll just run through all of them! | |
apiCallsToMake.forEach((runMe, index) => { | |
console.log(`\t(bad) call start ${index}`); | |
runMe(); | |
console.log(`\t(bad) call end ${index}`); | |
}); | |
console.log('=== DONE BAD 1 ==='); | |
} | |
// The problem is nothing is waiting for the forEach (which returns void) | |
// Not even the await, that's only causing | |
async function stillDoesNotWorkAsIntended() { | |
console.log('=== START BAD ASYNC ===='); | |
// Nothing is causing us to wait for each of the calls within, as forEach just keeps marching on | |
apiCallsToMake.forEach(async (runMe, index) => { | |
console.log(`\t(bad) call start ${index}`); | |
await runMe(); | |
console.log(`\t(bad) call end ${index}`); | |
}); | |
console.log('=== DONE BAD ASYNC ===='); | |
} | |
// ==== WORKING ===== | |
async function worksAsIntended() { | |
console.log('=== START GOOD 1 ==='); | |
const promisesForAllTheCalls = apiCallsToMake.map(async (runMe, index) => { | |
console.log(`\t(good) call start ${index}`); | |
await runMe(); | |
console.log(`\t(good) call end ${index}`); | |
}); | |
// THIS is the key! Promise.all will wait until all the promises in the | |
// array have returned! | |
await Promise.all(promisesForAllTheCalls); | |
console.log('=== DONE GOOD 1 ==='); | |
} | |
async function alsoWorksAsIntended() { | |
console.log('=== START GOOD 2 ==='); | |
const promisesForAllTheCalls = apiCallsToMake.map((runMe) => runMe()); | |
// THIS is the key! Promise.all will wait until all the promises in the | |
// array have returned! | |
await Promise.all(promisesForAllTheCalls); | |
console.log('=== DONE GOOD 2 ==='); | |
} | |
/** | |
* TODO: Uncomment ONE AT A TIME to see how things work | |
* | |
/* | |
NOTE: It should print out in this order: | |
TWO | |
ONE | |
ZERO | |
*/ | |
async function main() { | |
// ===== Broken on purpose ====== | |
await doesNotWorkAsIntended(); | |
// await stillDoesNotWorkAsIntended(); | |
// ======= These work! ========= | |
// await worksAsIntended(); | |
// await alsoWorksAsIntended(); | |
// this kills the node process to show how badly things can go if | |
// promises aren't handled properly | |
process.exit(1); // COMMENT THIS OUT TO SEE THE API RETURNING (broken tests only) | |
} | |
main(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Async for of loop Example | |
*/ | |
// timers in seconds | |
let x = [5,1,11,3]; | |
// sleep function | |
async function sleep(seconds, callback) { | |
if (Number.isNaN(seconds)) throw new TypeError('Seconds must be a number'); | |
return new Promise((resolve) => { | |
if (callback) { | |
setTimeout(() => resolve(callback), seconds * 1000); | |
} else { | |
setTimeout(resolve, seconds * 1000); | |
} | |
}); | |
} | |
// put in an async function so you can C&P to commandline | |
async function runDemo() { | |
for (const item of x) { | |
console.log('start', item) | |
await sleep(item, () => console.log('callback for ', item)) | |
console.log('done', item) | |
} | |
} | |
runDemo(); | |
/* expected output should be: | |
> runDemo(); | |
start 5 | |
Promise { <pending> } | |
callback for 5 | |
done 5 | |
start 1 | |
callback for 1 | |
done 1 | |
start 11 | |
callback for 11 | |
done 11 | |
start 3 | |
callback for 3 | |
done 3 | |
*/ | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// START Property Accessors | |
// This is an example of how you can access properties of an object in several ways | |
// The cool part is you can use variables to define the _keys_ you want to access | |
// allowing you to make generic functions and components that can access different variables dynamically. | |
// Real World example: Create a form that allows you to customize which DB column acts as the label and pass in the whole row object without worrying about preprocessing it | |
// example data setup | |
let company = { name: "norima", emails: [{type: 'work', address: 'a@example.com'}, {type: 'personal', address: 'b@example.com'}]}; | |
let anotherCompany = { name: "jamesco", emails: [{type: 'work', address: 'Ja@example.com'}, {type: 'personal', address: 'Jb@example.com'}]}; | |
let companies = { norima: company, jamesco: anotherCompany}; | |
// variables representing a more "real" scenario using customization or loops | |
let currentCompany = 'norima'; | |
let labelPropertyName = 'type'; | |
// access things | |
companies[currentCompany].emails[0][labelPropertyName] | |
companies.norima.emails[0].type; | |
// They're the same! | |
companies[currentCompany].emails[0][labelPropertyName] === companies.norima.emails[0].type; | |
// END Property Accessors |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment