So, not so long ago I had to face the quite popular task of converting asynchronous code to synchronous within a loop. In my case, it was working with AmazonAPI productSearch methods. Everything would be fine, but this API really doesn’t like it when it is accessed too often, and I needed to poll the state of the products in a cycle.
In this article, I will tell you about the implementation of the way I used to solve my problem using a practical example. Let's get started
For implementation, we need: promises (I will use the q library), a nodejs version with generator support, an experimental asynchronous function (we will use setTimeout).
var q = require("q"); function* itemGenerator(data) { var i, len = data.length; for(i = 0; i < len; i++) { yield data[i]; } } function oldIterator(data) { var i = -1, len = data.length; return { "next": function() { i++; return { "done": i == len, "value": data[i] }; } } } function main() { var def = q.defer(), items = [1, 2, 3, 4, 5]; (function foo(gen) { var genItem = gen.next(), item = genItem.value; if(genItem.done) { def.resolve(true); return; } console.log("start call for", item); setTimeout(function() { console.log("end call for", item); foo(gen); }); })(itemGenerator(items)) return def.promise; } main().then(function(flag) { console.log("promise has been resolved", flag); });
The result of this script will be:
')
> node async_sync.js start call for 1 end call for 1 start call for 2 end call for 2 start call for 3 end call for 3 start call for 4 end call for 4 start call for 5 end call for 5 promise has been resolved true
As we see, all our asynchronous calls go in a synchronous mode. To support older versions (that do not support generators), I added the “oldIterator” function, which will work similarly to the generator.
PS : this code will work in the same way in JavaScript, it is enough to replace the “Q” library with the native “Promise”.
That's all, thank you for your attention!