|
/* |
|
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); |
|
} |
|
|
So I apologize I didn't quite understand your code, and you might want to make some bug fixes as it doesn't work as-is atm.
I guessed at what you were trying to accomplish and reduced it down a bit. You can see from the numbers a pure asynchronous workload is magnitudes faster then a synchronous one. I verified the code against Node v12.14.1 and got similar timings.
The part I don't understand yet is when you mix synchronous and asynchronous code. The async workload seems to get locked with the sync work load. But you will see this is not the way Apps Script "implements" promises. This is how the V8 engine is currently working.
EDIT : I have a suspicion it has to do with 'console' in this case.