How to make ajax calls synchronous in JavaScript without blocking anything using ES6 generators

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.

What this article is NOT about

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.

What this article is about

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.

A bit on Generators

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.

Simple example

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.

Making calls one by one

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.

Conclusion

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

post-thumbnail
Today everyone knows the importance of a lightning-fast website and how the speed impacts the conversion rate of a business. Today, everyone wants the site to be a PWA so that the mobile users can have an app-like experience with the website because, for the majority of the merchants, the customers come through mobile devices.
Tue Apr 20 2021
post-thumbnail
Here we are going to see how you can manage backup and restore of Postgres database with docker.
Thu Sep 03 2020
post-thumbnail
Image sliders or carousels always have increased the UI attraction of websites and they are pretty useful for reflecting the major roles/products too. In case, I am having a website that sells tee-shirts,
Mon Apr 30 2018

About VoidCanvas

This blog was created out of hobby and talks mostly about technology, web development, JavaScript, NodeJS and related topics. Thank you for reading my blog.

Copyright 2022 - www.voidcanvas.com

Popular Articles

Authentication using Google's oAuth api with node.js

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.

CSS3 Loader Snippet Collection: (Part 2 - Squares)

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