if you want to keep itThere are some solutions for your issue with microtasks then you can do the followingusing native tasks. this one is using Promise to schedule a microtask:
(function() { function sum(arr, i = 0) { if(arr.length === i) { return Promise.resolve(0); } return Promise.resolve(null) .then(() => sum(arr, i + 1)) .then((x) => x + arr[i]); } sum(a).then(s => console.log(s)); }()); but this will force be the engine to wait until the execution is completed. So for huge arrays, I wouldn't recommend you doing this on the main thread.
You can also do the following:
(function() { function sum(arr, i = 0) { if(arr.length === i) { return Promise.resolve(0); } return new Promise(resolve => { setTimeout(() => { sum(arr, i + 1).then(x => resolve(x + arr[i])); }); }); } sum(a).then(s => console.log(s)); }()); then with makingmake a few changes to this code and making it more elegant, we can do the following:
(function() { const defer = () => new Promise((resolve) => setTimeout(resolve)); async function sum(arr, i = 0) { if(arr.length === i) { return 0 } await defer(); return await sum(arr, i + 1) + arr[i]; } sum(a).then(s => console.log(s)); }()); and if your environment supports tail recursion you can change this to use it: http://2ality.com/2015/06/tail-call-optimization.html
UPDATE
actually, there is one more way to do this. rxjs library provides a queue scheduler which can help you make a recursive logic to be iterative without making many changes in your code. I've created an example of your sum method here.