Collect Multiple JSONP Results - javascript

I have a javascript application that gets data from multiple jsonp requests. Once all of the data is returned the page will be updated with the new data. Below is pseudocode, but it's structured for a synchronous environment.
function GetAllData() {
var data1= GetData1();
var data2= GetData2();
var data3= GetData3();
UpdatePage(data1,data2,data3);
}
The issue I have is that I need to collect, and know, when all the data has been returned from the jsonp requests before I update the page. I was looking at jquery deferred, but I'm not sure if that's the correct solution.
Any suggestions would be appreciated.

Deferred is your correct solution, when you are using JQuery.
function GetData1() {
return $.ajax("/foo", ...);
}
function GetData2() {
return $.ajax("/bar", ...);
}
function GetData3() {
return $.ajax("/baz", ...);
}
function UpdatePage(data1, data2, data3) {
...
}
function Error() {
alert("An error occurred while fetching data");
}
function GetAllData() {
$.when(GetData1(), GetData2(), GetData3()).then(UpdatePage, Error);
}

Related

How do I return Vue resource without putting to data?

I want to return result directly (Normally we try to put to data and access that data yeah. but now how I want is directly). Like when we call hello() function I want to return result variable.
I try like the following, but it doesn't return yeah. How do I try?
hello: function() {
var result = "";
this.$http.get(window.location.href).success(function(data) {
result = data;
}).error(function (data, status, request) {
});
return result;
}
Looks like it doesn't return the data because the request is async. Your method sets up the request and then returns immediately, synchronously, before the request had a chance to assign any data to the result variable.
You can try to change your code slightly:
hello: function() {
var result = {};
this.$http.get(window.location.href).success(function(data) {
result.data = data;
result.ready = true;
}).error(function (data, status, request) {
});
return result;
}
That should enable you to access the data elsewhere (as result.data), but only after the async query has succeeded. The result.ready flag would tell you if and when that has happened.
In my opinion, it would definitely be better to work with promises, though, e.g. using jQuery Deferreds and promises, or ES6 promises along with a polyfill.

Extending done() in jQuery's Promise object

I'd like to wrap $.ajax().done() in a separate class, which includes validation of JSON responses against a schema.
A sample call could look like this:
myService.get("/api/people").done(function(people) {
// at this point I'm certain the data in people is valid
template.render(people);
}).catch(function() {
// this happens if validation of people failed, even if the request itself was successfull
console.log("empty json or validation failed");
});
The success callback function is passed in done(), but should only be executed if a private function (_validate(data, schema)) returns true. A less elegant version could look like this:
myService.get("api/people", successCallback, errorCallback);
I would like to expose the internal Deferred methods of $.ajax() directly. Is this possible?
You don't need to change the Promises. You can use then to layer promises.
function _validate(data, schema) {
return false;
}
var myService = {
get: function (data) {
return $.ajax(data).then(function (reply) {
if (_validate(reply, schema)) {
return reply;
} else {
// works if your library is Promises/A+ compliant (jQuery is not)
throw new Error("data is not valid JSON"); // causes the promise to fail
/*// else do:
var d = new $.Deferred();
d.reject("data is not valid JSON");
return d.promise();*/
}
});
}
}
myService.get("foo").done(function () { /* success */ }).fail(function () { /*failed */ });

Synchronously HTTPS GET with node.js

So I'm trying to preform a https GET with node.jsand I have the following code
function get(url) {
https.request(url, function(res) {
var data = "";
res.on('data', function (chunk) {
data += chunk;
})
.on('end', function(){
console.log(JSON.parse(data));
});
}).on('error', function(e) {
console.log(e.message);
}).end();
}
This code works fine and dandy except I need this function to return the data its logging
I know the recommended way to do this is to use callbacks, passing a callback function into get and then calling that function in the 'end' listener. But the problem is that this process needs to be synchronized and NOT pipelined because it causes data hazards and uses too much memory. On top of that, its is recursively called and is just one big headache to try and manage.
Basically, I'm trying to return JSON.parse(data) in the get function then the end listener is called, is that possible?
You can't synchronously return data using an asynchronous function to retrieve the data. Your get() function will return long before the https.request() has completed so you just can't do what you asked to do.
The usual design pattern for solving this involves passing in a callback function to your get() function that will be called when the data is available. This will involve restructing the caller of your function to handle an asynchronous response via a callback function.
There are some different choices in how you structure the callback, but here's the general idea:
function get(url, callback) {
https.request(url, function(res) {
var data = "";
res.on('data', function (chunk) {
data += chunk;
})
.on('end', function(){
callback("success", JSON.parse(data));
});
}).on('error', function(e) {
callback("error", e);
}).end();
}
Usage:
get("http://www.example.com/myurl", function(status, data) {
if (status === "success") {
console.log(data);
}
});
May I recommend Q. It is specifically designed to help you fight the famous pyramid of callbacks in JavaScript. I understand that callbacks can lead to less-readable code but you should not try to make synchronous get requests. It kind of defeats the advantages of node.js.
You can convert
step1(function (value1) {
step2(value1, function(value2) {
step3(value2, function(value3) {
step4(value3, function(value4) {
// Do something with value4
});
});
});
});
to this -->
Q.fcall(promisedStep1)
.then(promisedStep2)
.then(promisedStep3)
.then(promisedStep4)
.then(function (value4) {
// Do something with value4
})
.catch(function (error) {
// Handle any error from all above steps
})
.done();

How to convert callback sample to deferred object?

I have a function that accepts a callback function where I pass the data back in. Can this converted to a deferred object for better practice?
Here is what I got:
var chapters;
var getChapters = function (fnLoad) {
//CACHE DATA IF APPLICABLE
if (!chapters) {
//CALL JSON DATA VIA AJAX
$.getJSON('/chapters.txt')
.done(function (json) {
//STORE DATA IN LOCAL STORAGE
chapters = Lawnchair(function () {
this.save(json, function (data) {
//CALL CALLBACK ON DATA
fnLoad(data);
});
});
});
} else {
//RETURN ALREADY CREATED LOCAL STORAGE
chapters.all(function (data) {
//CALL CALLBACK ON DATA
fnLoad(data);
});
}
};
Then I simply use it like this:
this.getChapters(function (data) {
console.log(data);
});
How can I use it like a promise though while maintaining the cache approach?
this.getChapters().done(function (data) {
console.log(data);
});
var chapters;
var getChapters = function (fnLoad) {
var d = new $.Deferred();
//CACHE DATA IF APPLICABLE
if (!chapters) {
//CALL JSON DATA VIA AJAX
$.getJSON('/chapters.txt')
.done(function (json) {
//STORE DATA IN LOCAL STORAGE
chapters = Lawnchair(function () {
this.save(json, function (data) {
//CALL CALLBACK ON DATA
d.resolve(data);
});
});
})
.fail(function() { d.reject(); });
} else {
//RETURN ALREADY CREATED LOCAL STORAGE
chapters.all(function (data) {
//CALL CALLBACK ON DATA
d.resolve(data);
});
}
return d.promise();
};
Relevant example
I see you have already accepted an answer, however if you take a large mental leap and store a promise of chapters instead of the chapters themselves, then the code will simplify significantly.
These days, this is probably the more generally adopted approach for a "fetch/cache" situation.
var chapters_promise;
var getChapters = function () {
//Cache data if applicable and return promise of data
if (!chapters_promise)
chapters_promise = $.getJSON('/chapters.txt').then(Lawnchair).then(this.save);
return chapters_promise;
};
What is actually promised (the chapters) will be determined by the value(s) returned by the functions Lawnchair and this.save, so you still have some work to do.
getChapters() will always return a promise, regardless of whether the data needs to be fetched or is already cached. Therefore, getChapters() can only be used with promise methods .then(), .done(), .fail() or .always(), for example :
getChapters().then(fnLoad);
You have no other way to access the chapters but that is reasonable since at any call of getChapters(), you don't know whether it will follow the $.getJSON() branch or the simple return branch, both of which return an identical promise.

Continue loop after a function has finished executing. How to use jquery deffered

I have the following data
var data = [{user:"somename"}, {user:"anothername"}];
I have this function that processes that that, let say checking user if it exist
function process(user) {
$.ajax({
url: 'http://domain.com/api',
success: function(result) {
if(result == 'success')
anotherFunction();
else
console.log('error');
}
})
}
function anotherFunction() {
$.ajax({
// do stuffs
})
}
$.each(data, function(k,v){
process(v.user);
})
The $.each will try to loop even the process and the anotherFunction hasn't finished yet
Question, what can I do to assure that all functions are finished executing before moving on to another index?
I heard I can use jquery deferred.
Collect the promises returned by your AJAX function, if necessary post-processing that result with .then so that it calls anotherFunction() which must also return the result of $.ajax.
function process() {
return $.ajax(...).then(function(result) {
if (result === 'success') {
return anotherFunction();
} else {
return null; // this might need to change...
}
});
}
function anotherFunction() {
return $.ajax(...);
}
var promises = [];
$.each(data, function(k, v) {
promises.push(process(v.data));
}
and then wait for all the promises to be resolved:
$.when.apply($, promises).done(function() {
// all done here
});
NB: in general it's good practise for an AJAX call to produce a non 2xx return code for errors, rather than an error code within a "successful" HTTP call. This then allows the client side code to use normal AJAX error processing (i.e. .fail callbacks) instead of checking for "errors" within AJAX success processing.

Categories

Resources