This Gist was automatically created by Carbide, a free online programming environment.
You can view a live, interactive version of this Gist here.(http://alpha.trycarbide.com/anonymous/f7f61a345d7e7880eea3b1326e3d4d3d).
import slowDiv from "./promises.js"; | |
Promise.all([ ///All will return the results of all the promises (or reject at the first failure). | |
slowDiv(900, 3), | |
slowDiv(300, 100, 100), | |
slowDiv(5000, 10, 1000), | |
slowDiv(253, 11, 750) | |
]).then(results => console.log(results)); | |
Promise.race([ ///Race will return the result of the first promise to resolve or reject. | |
slowDiv(900, 3), | |
slowDiv(300, 100, 100), | |
slowDiv(5000, 10, 1000), | |
slowDiv(253, 11, 750) | |
]).then(results => console.log(results)); |
import slowDiv from "./promises.js"; ///We're just reusing code from earlier... | |
async function asyncDiv(a, b, ms = 500) { ///Asynchronous functions are tagged with "async" | |
return await slowDiv(a, b, ms); ///We can await anything that returns a promise, including async functions, since they also return promises. | |
} | |
async function chainedDivision() { | |
const r1 = await asyncDiv(900, 3), | |
r2 = await asyncDiv(r1, 2), | |
r3 = await asyncDiv(r2, 5); | |
return r3; ///Each await above proceeds in serial, waiting until the previous promise is resolved. | |
} | |
async function altChainedDivision() { | |
return await asyncDiv(await asyncDiv(await asyncDiv(900, 3), 2), 5); ///We don't have to use temp variables if we don't want too... although this is harder to read, IMO. | |
} | |
async function go() { | |
const a = await chainedDivision(), ///We can only use "await" inside "async" functions. | |
b = await altChainedDivision(); | |
console.log(a, b); | |
try { ///Inside "async" functions, if an await function throws an error, we can catch it using regular try...catch. | |
const c = await asyncDiv(5, 0); | |
} catch (err) { | |
console.error(err.message); | |
throw err; | |
} | |
} | |
go() ///We can call async functions outside side of an async function, but it will then be treated like a promise. | |
.catch(err => console.log(err.message)); ///... which means we can catch any thrown errors using the typical promise catch handling. | |
async function inSerial() { ///Be careful how you use it -- even code that looks like it might operate in parallel doesn't! | |
performance.now(); | |
const arr = [await asyncDiv(900, 3), ///Each of these processes in serial, waiting for the previous item in the array to finish. | |
await asyncDiv(300, 100, 2000), | |
await asyncDiv(5000, 10, 1000), | |
await asyncDiv(253, 11, 5000)]; | |
performance.now(); ///As you can see, ~8s have passed, not the ~5s that should have passed if these were operating in parallel. | |
return arr; | |
} | |
inSerial() | |
.then(results => console.log(results)); | |
async function all(...promiseFns) { ///Here we show that async functions work well with promises -- we're explicitly returning a Promise that's waiting on all the promise factories passed in to finish. | |
return await Promise.all(promiseFns.map(promiseFn => promiseFn())); | |
} | |
all(async () => await asyncDiv(900, 3), ///Arrow functions can be async too -- just have "async" in front. | |
async () => await asyncDiv(300, 100, 100), | |
async () => await asyncDiv(5000, 10, 5000), | |
async () => await asyncDiv(253, 11, 750)) | |
.then(results => console.log(results)); ///Because we're at the top level, we have to treat "all" like a promise, not like an async function. | |
function all2(...promiseFns) { | |
return Promise.all(promiseFns.map(promiseFn => promiseFn())); | |
} | |
// note, this works at the top level because carbide wraps us with a function, so it's not really the top level | |
const results = await all2(async () => await asyncDiv(900, 3), | |
async () => await asyncDiv(300, 100, 100), | |
async () => await asyncDiv(5000, 10, 5000), | |
async () => await asyncDiv(253, 11, 750)); | |
results; |
function slowDivCB(successCB, errorCB, a, b, ms = 500) { ///**ES5 Callbacks and Pyramid of Doom** | |
setTimeout(function() { | |
if (b === 0) errorCB(new Error("Can't divide by zero")); | |
else successCB(a / b); | |
}, ms); | |
} | |
slowDivCB(function (r) {console.log(r);}, function (err) {console.err(err);}, 10, 2); | |
slowDivCB(function (c) { | |
slowDivCB(function (d) { | |
slowDivCB(function (e) { | |
console.log(e); ///Imagine... it could be even worse than this! | |
}, function (err) {console.error(err);}, d, 2) | |
}, function (err) {console.error(err);}, c, 5) | |
}, function (err) {console.error(err);}, 900, 3); |
This Gist was automatically created by Carbide, a free online programming environment.
You can view a live, interactive version of this Gist here.(http://alpha.trycarbide.com/anonymous/f7f61a345d7e7880eea3b1326e3d4d3d).
function slowDiv(a, b, ms = 500) { ///**ES2015 and Promise Chaining** | |
return new Promise((resolve, reject) => { | |
setTimeout(() => { | |
if (b === 0) { | |
reject(new Error("Can't divide by zero")); | |
} else { | |
console.log(a / b); | |
resolve(a / b); | |
} | |
}, ms); | |
}); | |
} | |
slowDiv(900, 3) ///Much better! It's obvious that each step proceeds in serial, and what the order of operations will be. | |
.then(c => slowDiv(c, 5)) | |
.then(d => slowDiv(d, 2)) | |
.then(e => console.log(e)) | |
.catch(err => console.error(err)); | |
export default slowDiv; |
Promise.resolve(42) ///If we know the value, we can resolve it immediately | |
.then(n => console.log(n)); | |
Promise.reject(new Error("Can't answer that question!")) ///The same applies to rejection | |
.then(n => console.log(n)) | |
.catch(err => console.error(err.message)); | |
function altSlowDiv(a, b, ms) { ///Here's an alternate way of writing slowDiv() using Promise.resolve instead of new Promise() | |
return Promise.resolve({ | |
then: (resolve, reject) => { | |
setTimeout(() => { | |
if (b === 0) { | |
reject(new Error("Can't divide by zero")); | |
} else { | |
resolve(a / b); | |
} | |
}, ms); | |
} | |
}); | |
} | |
altSlowDiv(700, 3) | |
.then(c => altSlowDiv(c, 5)) | |
.then(d => altSlowDiv(d, 2)) | |
.then(e => console.log(e)) | |
.catch(err => console.error(err)); |
{ ///So why should we use Promise.resolve() even if we don't know the value immediately? Easy -- it's because of error handling. This couldThrow() function can throw an error BEFORE returning a promise. | |
const couldThrow = function(a, b) { | |
if (b === 0) throw new Error("b is zero!"); | |
return new Promise(resolve => resolve(a / b)); | |
} | |
try { | |
couldThrow(10, 0) | |
.then(r => console.log(r)) | |
.catch(err => console.error(err.message)); | |
} catch (err) { | |
console.error(`from outer catch: ${err.message}`); ///Which means that we have to have TWO error handling mechanisms. Also note that the catch in the promise chain NEVER gets called. | |
} | |
} | |
{ | |
const couldThrow = function(a, b) { | |
return Promise.resolve() ///Now we return a promise, _no matter what._ | |
.then(() => { | |
if (b === 0) throw new Error("b is zero!"); | |
return a / b; | |
}); | |
} | |
couldThrow(10, 0) ///Which means we know that any errors will be passed to our catch handler. | |
.then(r => console.log(r)) | |
.catch(err => console.log(err.message)); | |
} |