Fri Feb 05 2016
Paul Shan
Have you ever been in a situation where you have more than one calls, but you want them to be fired one by one? I have come across a similar scenario and here I am writing about the solution of the problem.
This is not about something like the code snippet below.
var responseObj = ajax("http://a-url.com/"); doWhateverYouWant(responseObj);
If you use jQuery’s $.ajax() method with async:false you will be able to do what is given in the code snippet above. But this is a dangerous thing to do. As JavaScript is single threaded; this operation of your will entirely hang your application till the server sends the response.
This is about making calls one after another. But till the time server responses for a call the thread will be free to do other operations (but not the second call). The concept of promise or callbacks will remain here. We will create a intermediate way just to make the calling part (you may make any other operation synchronous using the same approach) one after another.
JavaScript is moving fast. In ES7 they will provide async keyword to work similar to that in dot net. To do that they already set the basic in ES6. That basic part is called generator. ES6 features are not 100% implemented in all browsers. So it’s better to use ES6 shims if you are working in client side. The current version of node.js already supports generators, so you don’t have to worry if you are a node guy.
Generator functions can use a keyword called yield which can pause the further execution of that particular generator till the .next() function is called.
function asyncTask (index) { console.log("New Async "+index+" started") setTimeout(function () { console.log("Async task "+index+" stopped"); console.log("-----------------------------"); myFoo.next(); },4000); } function* syncRunner(){ var index =1; while (index <= 5){ yield asyncTask(index); index++; } } var myFoo = syncRunner(); myFoo.next(); //start it // output // New Async 1 started // Async task 1 stopped // ----------------------------- // New Async 2 started // Async task 2 stopped // ----------------------------- // New Async 3 started // Async task 3 stopped // ----------------------------- // New Async 4 started // Async task 4 stopped // ----------------------------- // New Async 5 started // Async task 5 stopped // -----------------------------
In the above example I have an asyncTask function which performs an async task, which may be an ajax call. I have another generator function named syncRunner which calls the async function and uses yield to halt.
Once the setTimeout() is resolved and the callback is called, I am calling the .next() function of the generator which works as a pause breaker.
Suppose you are creating a service to make this synchronous thing for you. That service function will return you a promise which you will handle exactly as you handle your normal async ajax call.
var syncTaskPointer = null; var requestsQueue = []; var requestResolveCallbackQueue = []; function nativeAjax (requestObj) { //this is your actual ajax function //which will return a promise //after finishing the ajax call you call the .next() function of syncRunner //you need to put it in the suceess callback or in the .then of the promise $.ajax(requestObj).then(function (responseData) { (requestResolveCallbackQueue.shift())(responseData); syncTaskPointer.next(); }); } function* syncRunner(){ while(requestsQueue.length>0){ yield nativeAjax(requestsQueue.shift()); } //set the pointer to null syncTaskPointer = null; console.log("all resolved"); }; ajaxSync = function (requestObj) { requestsQueue.push(requestObj); if(!syncTaskPointer){ syncTaskPointer = syncRunner(); syncTaskPointer.next(); } return new Promise(function (resolve, reject) { var responseFlagFunc = function (data) { resolve(data); } requestResolveCallbackQueue.push(responseFlagFunc); }); } ajaxSync("http://myApis.com/getUser"); ajaxSync("http://myApis.com/getHisFriends"); ajaxSync("http://myApis.com/unfriendThisParticularFriend"); ajaxSync("http://myApis.com/dateHisGirlFriend");
The above piece of code will not fire all the calls in parallel, even though you just called the ajaxSync() function 4 times one by one. This will fire the first call and wait till it gets resolved. After that it will find the syncTaskPointer.next(); and the generator will resume. Thus the next call will be fired.
The request objects are stored in a array which is working as a queue here and the response callbacks are also stored in another similar queue. You can even use JavaScript’s Object.observe() to handle promise resolve without using the callback queue.
Making JavaScript synchronous is a very bad idea. You can use the web workers if you want to do such task. But the preferred way to make synchronous thing is, just make that portion of your code synchronous which is necessary, not the rest part. This article explained how just the ajax calling part can be made synchronous. If your call 2 has dependency on your call 1; you can do your stuffs accordingly in the success function of call 1. And before firing call 2 you can set things up.
SHARE THIS ARTICLE
Thu Mar 10 2016
OAuth authentications are pretty popular now a days and another thing which is popular is JavaScript. This article shows how to plugin google’s oAuth api for authentication in your own node application.Sat Mar 01 2014
This is a continuation of my CSS3 loader snippet collection series. I've provided spinning css3 animation loader in the part 1 of this series and here in part 2, I'm providing various square type loading