|
/* |
|
Wherein I set out to demonstrate that even though Google V8 engine syntax includes async and Promises |
|
it is async in syntax only, and not in implementation. |
|
|
|
The code below takes async function and runs them in parallel with `Promises.all` |
|
But it is clear from the timing that it runs syncronously. |
|
*/ |
|
|
|
/* |
|
The promise returned in this function should resolve itself in 5 seconds, and running three of them |
|
in parallel should also take 5 seconds. |
|
Instead, an error is thrown as setTimeout is a `ReferenceError` and is undefined. |
|
It is expected that on the first error thrown, it stops the other two (does not throw three errors). |
|
(That setTimeout is a ReferenceError probably be the only clue we need that the stack is not async.) |
|
*/ |
|
function useSetTimeout () { |
|
const fiveSeconds = 5000; |
|
return new Promise(resolve => setTimeout(resolve, fiveSeconds)); // ReferenceError: setTimeout not defined |
|
} |
|
|
|
async function calc(i, j) { |
|
return i + j; |
|
} |
|
|
|
/* |
|
The promise returned in this function should resolve itself in about 7 seconds, and running three of them |
|
in parallel should also take about 7 seconds. |
|
Instead, it takes 24 seconds (your mileage may vary) ... as if it had to run three times syncronously |
|
(This indicates that it isn't being run in parallel like it should be.) |
|
*/ |
|
function useForLoop () { |
|
return new Promise( resolve => { |
|
let total = 0; |
|
for (let i = 0; i <= 10000; i++) { |
|
for (let j = i; j > 0; j--) { |
|
total += await calc(i + j); |
|
} |
|
} |
|
resolve("completed"); |
|
} ); |
|
} |
|
|
|
/* |
|
This function does the work of attempting to run the async functions in paraellel. |
|
*/ |
|
async function concurrency(func) { |
|
let promises = []; |
|
promises.push(func()); |
|
promises.push(func()); |
|
promises.push(func()); |
|
// Send an array of promises which should be executed |
|
let results = await Promise.all(promises); |
|
return results; |
|
} |
|
|
|
/* |
|
This function implements timing, calls `concurrency`, which hands off to the intended asyncFunction |
|
*/ |
|
function timeit (asyncFunction) { |
|
const start = new Date().getTime(); |
|
concurrency(asyncFunction).then(result => { |
|
const end = new Date().getTime(); |
|
const duration = (end - start) / 1000; |
|
Logger.log(`function ${asyncFunction.name} took ${duration} seconds to complete`); |
|
}).catch(error => { |
|
Logger.log(error); |
|
}); |
|
} |
|
|
|
/* |
|
Execute this function from the play button in the online editor |
|
*/ |
|
function entrypoint () { |
|
timeit(useSetTimeout); |
|
timeit(useForLoop); |
|
} |
|
|
OK I did some more testing and now coming to agree with you when you mix in App Script services. Take the following example:
The Promise.All is being processed serially when you add an Apps Script service.. It's like there is a separate stack for App Script service calls. When ever a call to a service happens it get added to the stack and that is processed serially. So Promise.all just adds the call to the stack faster then adding is serially. No real time savings. It only makes sense if your Promise.all is doing something computationally expensive in addition to the Apps Script service call which if you look at my last comment is much faster.