I'm using defer's .done to wait for a cookie to be loaded before the function finishes. When I try to run the code it finishes and returns undefined. It seems like .done is firing before the first code can finish.
function getCookie(cookieName){
var value;
var defer = new jQuery.Deferred();
fetchCookie().done(
function(){
return value;
}
);
function fetchCookie(){
chrome.cookies.get(
{
'url':'https://addictedtogether.com/',
'name':cookieName
},
function(data){
console.log(data);
value=data.value;
}
);
return defer.promise();
}
}
//usage
var username=getCookie('username');
Deferred objects won't let you avoid callbacks. You still would need to be doing something like this (assuming everything is implemented correctly):
getCookie('username').then(function(username){
console.log(username);
});
It will just generate unneeded overhead. I would rather simply do:
function getCookie(cookieName, callback){
chrome.cookies.get(
{
'url':'https://addictedtogether.com/',
'name':cookieName
},
function(data){
console.log(data);
value=data.value;
if(callback) {
callback(value);
}
}
);
}
//usage
getCookie('username', function(username){
console.log(username);
});
Related
I have a javascript code which have to request the database (ajax). But I discovered that the inserts were wrong but with the right sql request. So I added an alert on which ajax request to know when the code is executed.
Here is the code :
$.post("/kohana-v3.3.5/ajax/update_simulation", {
id_simulation: id_simulation,
nom_simulation: nom_simulation,
sol_simulation: sol_simulation,
station_simulation: station_simulation,
iteration_simulation: iteration_simulation,
scenario_simulation: scenario_simulation
}
, function (result) {
console.log(result);
alert('update');
});
$.post("/kohana-v3.3.5/ajax/delete_pousses", {id_simulation: id_simulation}, function (result) {
console.log(result);
alert('delete');
});
$(this).prev('div').find('table .formRows').each(function (i) {
alert('here');
if (cpt % 2 == 1) {
//interculture
var $tds = $(this).find('td option:selected'),
culture = $tds.eq(0).val(),
date = $tds.eq(1).text();
itk = null;
} else {
//culture
var $tds = $(this).find('td option:selected'),
culture = $tds.eq(0).val(),
itk = $tds.eq(1).val();
date = null;
}
$.post("/kohana-v3.3.5/ajax/insert_pousses", {
id_simulation: id_simulation,
culture: culture,
date: date,
itk: itk,
rang: cpt
}, function (result) {
console.log(result);
alert('insert');
}); //Fin du post
cpt++;
}); //Fin du each
Each time I run that code, the order of the alert is always different ! Sometimes "insert update delete", sometimes "update, delete insert" ...
And it's a problem because if the delete is the last one, the insert will be removed. So, is it a normal way ? How should I resolve it ?
javascript can be executed asynchronously - and that's the reason why your ajax requests are not always executed in the same order. You can set them asnyc false (like here jQuery: Performing synchronous AJAX requests) or make something like promises (https://api.jquery.com/promise/) to wait for the ajax call to be finished.
greetings
AJAX requests are asynchronous, so you cannot guarantee an order if you trigger them as siblings like this.
In order to guarantee a fixed order, you need to make the subsequent call from the success block of its predecessor. Something like this:
$.post('/ajax/method1', { params: params },
function(result) {
$.post('/ajax/method2', { params: params },
function(result) {
$.post('/ajax/method3', { params: params },
function(result) {
});
});
});
You can use .promise to "observe when all actions of a certain type bound to the collection, queued or not, have finished."
https://api.jquery.com/promise/
Example Function
function testFunction() {
var deferred = $.Deferred();
$.ajax({
type: "POST",
url: "",
success: function (data) {
deferred.resolve(data);
}
});
return deferred.promise();
}
Calling Function
function CallingFunction()
{
var promise = testFunction();
promise.then(function (data) {
//do bits / call next funtion
}
}
Update
This may also help you out:
"Register a handler to be called when all Ajax requests have completed."
https://api.jquery.com/ajaxStop/
$(document).ajaxStop(function () {
});
Final note:
As of jQuery 1.8, the use of async: false is deprecated, use with $.Deferred.
you need to call post ajax method after by the success of previous one.
like:
$.post("/kohana-v3.3.5/ajax/update_simulation", {
id_simulation: id_simulation,
nom_simulation: nom_simulation,
sol_simulation: sol_simulation,
station_simulation: station_simulation,
iteration_simulation: iteration_simulation,
scenario_simulation: scenario_simulation
}
, function (result) {
console.log(result);
alert('update');
dleteajax();
});
function dleteajax()
{
$.post("/kohana-v3.3.5/ajax/delete_pousses", {id_simulation: id_simulation}, function (result) {
console.log(result);
alert('delete');
});
}
Imagine i have a simple javascript function:
function someFunction(integer)
{
data = integer + 1;
return data;
}
I need to call this from inside another function and use the returned value:
function anotherFunction(integer)
{
int_plus_one = someFunction(integer);
//Do something with the returned data...
int_plus_two = int_plus_one + 1;
return int_plus_two;
}
How can i ensure that the return of anotherFunction return is only returned after someFunction completes? It actually seems to work ok with very fast functions like these. However if someFunction has to do some ajax lookups, the return of aotherFunction fails.
Thanks,
Steve
You do not know when or even if an asynchronous function will complete. The only way to handle this is to use a callback function, a function that gets executed after the async operation has completed.
This was my "aha!" moment: How to return the response from an asynchronous call?
As far as your code is sync, the approach above is fine.
Once you start introducing async parts, the one below involving callbacks is a common used approach:
function fn (v, cb) {
doSomethingAsyncWithV(function (err, _v) {
if(err) return cb(err);
cb(null, _v);
})
}
function yourFirstFn () {
var v = 0;
fn(v, function (err, _v) {
// do here whatever you want with the asynchronously computed value
});
}
How about promise? With that in mind, there's no need to worry about callback. It's one of the cool things in AngularJS.
var q = require('q');
var myPromise =function() {
var deferred = q.defer();
setTimeout(function(){
var output = anotherFunction(1);
deferred.resolve(output)
}, 10000); // take times to compute!!!
return deferred.promise;
}
var objPromise = myPromise();
objPromise.then(function(outputVal){
console.log(outputVal) ; // your output value from anotherFunction
}).catch(function(reason) {
console.log('Error: ' + reason);
})
then is ONLY exeucted after promise has been resolved. If an exception or error is caught, the catch function executes.
how about this?
function someFunction(integer, callback)
{
data = integer + 1;
return callback(data);
}
function anotherFunction(integer)
{
int_plus_one = someFunction(integer, function(data){
int_plus_two = int_plus_one + 1;
return int_plus_two;
});
//Do something with the returned data...
}
You could use promises:
new Promise(function someFunction(resolve, reject) {
ajaxLib.get(url, options, function (data) {
resolve(data);
});
}).then(function anotherFunction(integer)
{
int_plus_one = integer;
//Do something with the returned data...
int_plus_two = int_plus_one + 1;
return int_plus_two;
});
If you use jQuery, $.ajax returns a thenable :
$.ajax(url, options).then(function processDataFromXHR(data) {
return data.integer;
}).then(function anotherFunction(integer){
int_plus_one = integer;
//Do something with the returned data...
int_plus_two = int_plus_one + 1;
return int_plus_two;
});
I need to wait until all my ajax functions are done, and then continue the exectution.
My particular case is that I need to translate some fields in a form before submitting it. I translate them with an ajax call to an external site. Depending on some values in the form i would need to do more or less translations. When all the translations are done (if any) I have to validate the form with ajax, and if its valid, then submit.
This is my aproach:
First, I have a function that sends the ajax call and do stuff with the data received:
function translate(...) {
$("#ajaxCounter").val(parseInt($("#ajaxCounter").val()) + 1);
$.ajax({
...
success:function(data) {
...
$("#ajacCounter").val(parseInt($("#ajaxCounter").val()) - 1);
}
});
Then, when the form is to be submitted I execute the following code:
$("#form").submit(function() {
translatable_fields.each(function() {
translate(...);
});
while (parseInt($("#ajaxCounter").val()) > 0) { null; }
if (!(this).hasClass('ready')) {
$.ajax({
//validation
success: function(data) {
if (data['isValid']) {
$("#form").addClass('ready');
$("#form").submit();
}
}
});
}
return true;
});
The problem is that the while loop in the submit function never ends.
If I execute the code without the while loop I can see the ajaxCounter input increasing when the translation functions start and decreasing when they end.
You can achieve this in a much neater fashion using the deferred objects returned from a $.ajax call. First you should get the translate() function to return the deferred:
function translate(...){
return $.ajax({
// settings...
});
});
Then you can put all those promises in to a single array:
var requests = [];
translatable_fields.each(function(){
requests.push(translate(...));
});
Then you can apply that array to $.when:
$.when.apply($, requests).done(function(schemas) {
console.log("All requests complete");
// do something...
});
You can do this using deferred objects, but you do not need to use $.when.apply with an array if you are only interested in the final completion.
Instead you can chain parallel promises using the pattern promise = $.when(promise, another promise)
Change your translate to return the Ajax promise:
function translate(...) {
...
return $.ajax({
...
});
}
and your promise loop simply becomes:
var promise; // Start with an undefined promise - which is the same as a resolved promise for $.when
translatable_fields.each(function() {
promise = $.when(promise, translate(...));
});
// Wait for all promises to complete
promise.done(function(){
// now do the final code after all the ajax calls complete
});
Notes:
This does create an extra promise per call to $.when, but the overhead is very small and the resulting code is quite simple.
No, you can't just loop like this: the callbacks would never get a chance to be called.
I would do something like this:
function translateAllFields(done) {
var requestsInProgress = 0, doneCalled = false;
translatable_fields.each(function () {
++requestsInProgress;
$.ajax({
//...
success: function (data) {
//...
$("#ajacCounter").val(parseInt($("#ajaxCounter").val()) - 1);
}
}).always(function () {
if (--requestsInProgress === 0) {
done();
doneCalled = true;
}
});
});
if (requestsInProgress === 0 && !doneCalled) {
// in case translatable_fields was empty
done();
}
}
and then:
$("#form").submit(function (e) {
if (!(this).hasClass('ready')) {
e.preventDefault();
e.stopPropagation();
translateAllFields(function() {
$.ajax({
//validation
success: function (data) {
if (data['isValid']) {
$("#form").addClass('ready');
$("#form").submit();
}
}
});
});
}
});
You can use callback
function translate(..., callback) {
$.ajax({
...
success:function(data) {
...
callback(data);
}
});
};
And pass your after ajax code to it
$("#form").submit(function() {
translatable_fields.each(function() {
translate(..., function(result){
if (!(this).hasClass('ready')) {
$.ajax({
//validation
success: function(data) {
if (data['isValid']) {
$("#form").addClass('ready');
$("#form").submit();
}
}
});
}
return true;
});
});
});
Lets say I wanna send an email then update the database, both actions are async. This is how I would normally write it.
send_email(function(err, id){
if(err){
console.log("error");
}else{
update_database(id,function(err, id){
if(err){
console.log("error");
}else{
console.log("success");
}
});
}
});
I would like to do this instead with middleware.
var mid = {};
mid.send_email = function(){
return function(next){
send_email(function(err,id){
if(err){
console.log("error");
}else{
next(id);
}
});
}
}
mid.update_database = function(){
return function(id,next){
update_database(id,function(err,id){
if(err){
console.log("error");
}else{
next(id);
}
});
}
}
mid.success = function(){
return function(id,next){
console.log("success")
next(id);
}
}
Stacking the middleware.
middleware.use(mid.send_email());
middleware.use(mid.update_database());
middleware.use(mid.success());
There are two main questions at hand.
How can I use middleware in place of nested callbacks?
Is it possible to pass variables to next()?
What you want is to be able to handle a async control flow. Alot of js library can help you to achieve this. You can try the Async library with the waterfall function since you want to be able to pass variables to the next function that will be executed :
https://github.com/caolan/async#waterfall
"Runs an array of functions in series, each passing their results to the next in the array. However, if any of the functions pass an error to the callback, the next function is not executed and the main callback is immediately called with the error."
Example :
async.waterfall([
function(callback){
callback(null, 'one', 'two');
},
function(arg1, arg2, callback){
callback(null, 'three');
},
function(arg1, callback){
// arg1 now equals 'three'
callback(null, 'done');
}
], function (err, result) {
// result now equals 'done'
});
You are probably better off using CommonJS module.exports.
You can create a file like this:
module.exports = function (){
function sendEmail(doneCallback){
// do your stuff, then when you are done:
if(!err){
doneCallback(whatever,args,you,need);
}
}
function updateDB(success){
// do your stuff, then when you are done:
success(whatever,args,you,need);
}
return {
send: sendEmail,
update: updateDB
};
};
Then in your server.js:
var lib = require('./mylib.js');
lib.send(function(result){
console.log(result);
});
This is a similar pattern, and it might give you a better idea of what I mean. It consists of the library baking a function and passing it to whoever needs to chain, like this (more down to earth example, client-side this time):
ui.bistate($('#mybutton'), function(restore){
$.ajax({
url: '/api/1.0/catfood',
type: 'PUT',
data: {
catfood: {
price: 1.23,
name: 'cheap',
text: 'Catzy'
}
}
}).done(function(res){
// stuff with res
restore();
});
});
and in the library, this is how restore is provided:
var ui = function(){
function bistate(button, action) {
var originalText = buttonText.data('text'),
disabledText = buttonText.data('text-disabled');
function restore(){
button.prop('disabled', false);
button.text(originalText);
}
function disable(){
button.prop('disabled', true);
button.text(disabledText);
}
button.on('click', function(){
disable();
action(restore);
});
restore();
}
return {
bistate: bistate
};
}();
Allowing the consumer to control the flow for when he wants to restore the button, and reliving the library from having to handle complex cases where the consumer wants to do an async operation in between.
In general the point is: passing callbacks back and forth is huge and not used widely enough.
I have been using Queue.js in my work for some time.
I'm trying to write an procedure that does something after 2 objects are returned as a result of the callback of an ajax function.
I know the classic example of using Jquery when():
$.when($.get("http://localhost:3000/url1"),
$.get("http://localhost:3000/url2").done(//do something));
But in my case, I don't want to trigger the when on the execution of the ajax function, I want the when to trigger from the callback from the execution of the ajax function. Something like:
$.get("http://localhost:3000/url1", function(data){
function(){
//do something with the data, and return myobj1;
}
});
$.get("http://localhost:3000/url2", function(data){
function(){
//do something with the data, and return myobj2;
}
});
$.when(obj1, obj2).done(function(){
//do something with these 2 objects
});
But of course, that doesn't work. Ideas?
That actually should work. jQuery.when() takes multiple arguments and fires once they all have completed returning each results arguments as an array:
var req1 = $.get("http://localhost:3000/url1");
var req2 = $.get("http://localhost:3000/url2");
$.when(req1, req2).done(function(res1, res2) {
//do something with these 2 objects
});
If you don't want to handle the requests together you can create your own deferreds and use those:
var deferred1 = $.Deferred(),
deferred2 = $.Deferred();
$.get("http://localhost:3000/url1", function(data){
function(){
//do something with the data, and return myobj1;
deferred1.resolve(myobj1);
}
});
$.get("http://localhost:3000/url2", function(data){
function(){
//do something with the data, and return myobj2;
deferred2.resolve(myobj2);
}
});
$.when(deferred1, deferred2).done(function(){
//do something with these 2 objects
});
or you can do controls yourself
$(function(){$('body').addClass('doc-ready')})
var thingsToLoad = ['blabla.js','blublu.js','weee.js'];
var launch = function(){
// do whatever you want to do after loading is complete
// this will be invoked after dom ready.
// objectCollection will have everything you loaded.
// and you can wrap your js files in functions, and execute whenever you want.
}
var loadTester = (function() {
var loadCounter = 0,
loadEnds = thingToLoad.length; // total number of items needs to be loaded
return function() {
loadCounter += 1;
if (loadCounter === loadEnds) {
if ($('body').hasClass('doc-ready')) {
launch();
} else {
/* if body doesnt have ready class name, attach ready event and launch application */
$(function() {
launch();
});
}
}
}
}());
$.each(thingsToLoad, function(i) {
$.ajax({
url : thingsToLoad[i],
mimeType : 'application/javascript',
dataType : 'script',
success : function(data) {
loadTester();
}
});
});
add your files into thingsToLoad array,
at the end it will be iterated over and will be loaded after success, it will init
loadTester.
loadTester will check length of your thingsToLoad array, when number of loaded files vs files length matches and dom in ready status, it will launch().
if you're just loading html files, or text files, you can pass those (data in ajax function) into loadTester and accumulate there (within a private var like those loadCounter and loadEnds), and pass accumulated array or object to launch()