serializes ajax calls without interrupting by failure - javascript

I need to make a list of ajax calls execute sequentially. In other words,
one starts after another finishes.
I implement this by chaining jQuery promise. And I need the calls executed no matter the former ones succeeded or not. So I wrap the promise returned by jquery to a new one. It works. But I wonder if promise could support this case directly without using the wrap.
function getOne(apple) {
return $.get(apple)
.done(function() {
console.info("I'm done " + apple);
})
.fail(function() {
console.info("I fail " + apple);
});
};
function getAll(apples) {
return _.reduce(apples, function(result, apple) {
return result.then(function() {
var d = $.Deferred();
getOne(apple).always(function() {
d.resolve();
});
return d.promise();
})
}, $.when(1));
};

i hope this pseudo code helps:
var sequence = Promise.resolve();
for(loop){
sequence = sequence.then(function(url){
return ajaxGet(url);
}).catch(function(err){
console.log(err);
})
}
the idea is that you chain promises one after another, and the next one starts only when previous resolves or rejects.

Related

how to break for loop in promise?

var ing_data = savedata.ingredients.split(',');
for(var i =0; i<ing_data.length; i++){
var d = {
content_name: ing_data[i],
dogFoodId: dogId
}
db.dog_ingredients.create(d).then(function(data){
}, function(e){
console.log(e);
res.status(403).send('Error');
//break for loop this point
});
}
how to break for loop in promise?
I'm using node express, sequelize module
The loop will be over before the first then callback is triggered; this is one of the guarantees of promises (assuming that create operation returns a proper promise, not just a thenable; or at least that the thenable it returns completes asynchronously).
You can use the reduce trick to loop through adding those ingredients serially (one at a time); a promise rejection along the way will skip the remaining ingredients:
savedata.ingredients.split(',').reduce(function(p, ing) {
// Chain this ingredient on the end of the promise, return
// the new promise `then` returns, which gets passed to the
// next iteration
return p.then(function() {
var d = {
content_name: ing,
dogFoodId: dogId
};
// Return the promise from `create`
return db.dog_ingredients.create(d);
});
}, Promise.resolve()/* Seeds the loop above */)
.catch(function(e) {
// We got a rejection, which bypasses any pending resolution
// handlers we set up above; process the rejection.
console.log(e);
res.status(403).send('Error');
return Promise.reject(e); // Only need to propgate the rejection like this
// this if something will use the return value of
// this overall structure
});
That looks massive, but that's mostly comments and the object initializer; we could also write it like this (assuming we didn't need to propagate the rejection):
savedata.ingredients.split(',').reduce(function(p, ing) {
return p.then(function() {
return db.dog_ingredients.create({ content_name: ing, dogFoodId: dogId });
});
}, Promise.resolve())
.catch(function(e) {
res.status(403).send('Error');
});
(Or you can even get smaller, but for me debugging suffers — leave minifying to the minifier.)
I assume you don't want to add the ingredients in parallel since you've indicated you want to stop on the "first" error. But if you did, the code would be simpler:
Promise.all(savedata.ingredients.split(',').map(function(ing) {
return db.dog_ingredients.create({ content_name: ing, dogFoodId: dogId });
}).catch(function(e) {
res.status(403).send('Error');
return Promise.reject(e);
});
(Assumes we don't need to propagate the rejection.)
Again, though, that's parallel.

How can I return a promise from a recursive request and resolve it when the data matches a condition?

I'm consuming an API that returns JSON, and on this page I have a progress bar indicating various steps toward setting something up at the user's request. Each subsequent AJAX request's success callback initiates the next request, because they need to be done in sequence. One step issues a server-side background job and the endpoint returns a transaction ID.
Outside this flow there is a function that checks another endpoint to see if this transaction is complete or not. If it's "pending", I need to reissue the request after a small delay.
I had this working with a recursive function:
function checkTransaction(trxid) {
window.profileTrx[trxid] = 0;
trxurl = 'https://example.com/transaction/'+trxid;
$.getJSON(trxurl,function(result) {
if(result.status === 'pending') {
setTimeout(function () {
checkTransaction(trxid);
},3000);
} else {
window.profileTrx[trxid] = result;
}
});
}
The reason I was using window is so I could access the transaction by its ID in the callback it came from - a good use case for a promise if ever there were one. But it got messy, and my lack of experience began to get in my way. Looping over the state of window.profileTrx[trxid] seemed like double work, and didn't behave as expected, looping too quickly and crashing the page. Again, a promise with the next step in .then() was my idea, but I can't figure out how.
How could I implement this with promises such that the callback function that initiated the recursive "transaction check" would only continue with the rest of its execution once the API returns a non-pending response to the check?
I could get my head round recursing, and returning a promise, but not both at once. Any and all help massively appreciated.
My head is always clearer when I factor out promises first:
// wrap timeout in a promise
function wait(ms) {
var deferred = $.Deferred();
setTimeout(function() {
deferred.resolve();
}, ms);
return deferred.promise();
}
// promise to get a trxid
function getTRX(trxid) {
var trxurl = 'https://example.com/transaction/'+trxid;
return $.getJSON(trxurl);
}
Now the original function seems easy...
function checkTransaction(trxid) {
window.profileTrx[trxid] = trxid;
return getTRX(trxid).then(function(result) {
if (result.status === 'pending') {
return wait(3000).then(function() {
return checkTransaction(trioxid);
});
} else {
window.profileTrx[trxid] = result;
return result;
}
});
}
The caller will look like this:
return checkTransaction('id0').then(function(result) {
return checkTransaction('id1');
}).then(function(result) {
return checkTransaction('id2');
}) // etc
Remember, if the checkTransaction stays pending for a very long time, you'll be building very long chains of promises. Make sure that the get returns in some very small multiple of 3000ms.
"deferred"-based solution (not recommended)
Since you are using jQuery in your question, I will first present a solution that uses jQuery's promise implementation based on the $.Deferred() object. As pointed out by #Bergi, this is considered an antipattern.
// for this demo, we will fake the fact that the result comes back positive
// after the third attempt.
var attempts = 0;
function checkTransaction(trxid) {
var deferred = $.Deferred();
var trxurl = 'http://echo.jsontest.com/status/pending?' + trxid;
function poll() {
console.log('polling...');
// Just for the demo, we mock a different response after 2 attempts.
if (attempts == 2) {
trxurl = 'http://echo.jsontest.com/status/done?' + trxid;
}
$.getJSON(trxurl, function(result) {
if (result.status === 'pending') {
console.log('result:', result);
setTimeout(poll, 3000);
} else {
deferred.resolve('final value!');
}
});
// just for this demo
attempts++;
}
poll();
return deferred.promise();
}
checkTransaction(1).then(function(result) {
console.log('done:', result)
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
This should work (run the snippet to see), but as mentioned in the linked answer, there are issues with this "deferred" pattern, such as error cases not being reported.
The issue is that jQuery promises (until possibly recent versions - I've not checked) have massive issues that prevent better patterns from being used.
Another approach would be to use a dedicated promise library, which implements correct chaining on then() functions, so you can compose your function in a more robust way and avoid the "deferred" antipattern:
Promise composition solution (better)
For real promise composition, which avoids using "deferred" objects altogether, we can use a more compliant promise library, such as Bluebird. In the snippet below, I am using Bluebird, which gives us a Promise object that works as we expect.
function checkTransaction(trxid) {
var trxurl = 'http://echo.jsontest.com/status/pending?' + trxid;
var attempts = 0;
function poll() {
if (attempts == 2) {
trxurl = 'http://echo.jsontest.com/status/done?' + trxid;
}
attempts++;
console.log('polling...');
// wrap jQuery's .getJSON in a Bluebird promise so that we
// can chain & compose .then() calls.
return Promise.resolve($.getJSON(trxurl)
.then(function(result) {
console.log('result:', result);
if (result.status === 'pending') {
// Bluebird has a built-in promise-ready setTimeout
// equivalent: delay()
return Promise.delay(3000).then(function() {
return poll();
});
} else {
return 'final value!'
}
}));
}
return poll();
}
checkTransaction(1).then(function(result) {
console.log('done:', result);
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/bluebird/3.4.1/bluebird.min.js"></script>
You can return promises from functions, and the .then of the parent function will resolve when all the returned promises are resolved.
check this out for full details.
https://gist.github.com/Bamieh/67c9ca982b20cc33c9766d20739504c8

Parse.Query.each() chained promises

I'm writing a background job function on Parse.com CloudCode. The job needs to call the same function (that includes a Parse.Query.each()call) several times with different parameters, and I want to chain these calls with promises. Here's what I have so far:
Parse.Cloud.job("threadAutoReminders", function(request, response) {
processThreads(parameters1).then(function() {
return processThreads(parameters2);
}).then(function() {
return processThreads(parameters3);
}).then(function() {
return processThreads(parameters4);
}).then(function() {
response.success("Success");
}, function(error) {
response.error(JSON.stringify(error));
});
});
Below is the processThreads() function:
function processThreads(parameters) {
var threadQuery = new Parse.Query("Thread");
threadQuery... // set up query using parameters
return threadQuery.each(function(thread) {
console.log("Hello");
// do something
});
}
My questions are:
Am I chaining function calls using promises correctly?
What happens in threadQuery.each() returns zero results? Will the promise chain continue with execution? I'm asking because at the moment "Hello" never gets logged..
Am I chaining function calls using promises correctly?
Yes.
What happens in threadQuery.each() returns zero results? Will the promise chain continue with execution? I'm asking because at the moment "Hello" never gets logged.
I think I'm right in saying that, if "do something" is synchronous, then zero "Hello" messages can only happen if :
an uncaught error occurs in "do something" before a would-be "Hello" is logged, or
every stage gives no results (suspect your data, your query or your expectation).
You can immunise yourself against uncaught errors by catching them. As Parse promises are not throw-safe, you need to catch them manually :
function processThreads(parameters) {
var threadQuery = new Parse.Query("Thread");
threadQuery... // set up query using parameters
return threadQuery.each(function(thread) {
console.log("Hello");
try {
doSomething(); // synchronous
} catch(e) {
//do nothing
}
});
}
That should ensure that the iteration continues and that a fulfilled promise is returned.
The following example shows as use promises inside your function using a web browser implementation.
function processThreads(parameters) {
var promise = new Promise();
var threadQuery = new Parse.Query("Thread");
threadQuery... // set up query using parameters
try {
threadQuery.each(function(thread) {
console.log("Hello");
if (condition) {
throw "Something was wrong with the thread with id " + thread.id;
}
});
} catch (e) {
promise.reject(e);
return promise;
}
promise.resolve();
return promise;
}
Implementations of promise:
Web Browser https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
jQuery https://api.jquery.com/promise/
Angular https://docs.angularjs.org/api/ng/service/$q

Sequential function calls in javascript

I want function A to finish execution and only after that function B should start executing. When I call function A and then function B, it seems both are executing simultaneously. And after function B completes, I want to call a third function update_dropdown().
My code looks like this:
function A {
for (var i = 0; i < 5; i++) {
var promise = $.get(url+i);
$.when(promise).then(function () {
$.post(url);
});
}
}
function B {
var x = $.get(url);
var promise = $.post(url+x);
$.when(promise0).then(function () {
update_dropdown();
});
}
Please can you tell me how I can make these 3 function calls happen sequentially.
OK, it's getting a little bit clearer what you actually want (based on your recent comments to address clarifying questions) though there are still at least two options open.
For an operation like this, you probably want to take advantage of a number of promise features:
jQuery's Ajax calls already return a promise so you can just use those directly
To serialize operations, you can just chain multiple promise operations together
To make async operations serialize properly, you can return a promise from a .then() handler and the master promise will resolve only when all the chained promises have resolved (kind of a built-in $.when() without having to explicitly call $.when()).
You can chain as many operations together as you want and the master promise will tell you when they are all done.
If you return promises from both A() and B(), then the callers of those functions can monitor when they are done with promise methods which then lets you chain A().then(B) to sequence those two.
When you sequence operations with chaining, the prior methods resolve data is passed to the next .then() handler function in the chain as the first argument to the .then() handler function so if you need the prior data for the next operation, it is right there to use.
So, with all those capabilities, it's just a matter of putting the right scaffolding around the code to implement the exact sequencing you want. Here are two different options:
Option 1: If you want to serialize everything in A() so that all 10 requests happen in serial fashion (the next one proceeds only when the prior one is done), then it could look like this:
// serialize all requests
function A() {
var p = $.get(url).then(function(data) {return $.post(url)});
for (var i = 1; i < 5; i++) {
// chain four more pairs of requests onto the original promise
p = p.then(function() {return $.get(url)})
.then(function(data) {return $.post(url)});
}
// return the promise so callers can monitor when A() is done
return p;
}
function B() {
// sequence these three operations one after the other
return ($.get(url)
.then(function(data) {return $.post(url + x)})
.then(update_dropdown)
);
}
// run them both, one after the other
A().then(B);
Option 2: If you want the 5 pairs of requests in A() to run in parallel, with only the last part of A() waiting until the 5 pairs of requests are done, then it could look like this:
// parallelize pairs of requests
function A() {
var promises = [];
for (var i = 0; i < 5; i++) {
// execute 5 pairs of requests where each pair is serialized in itself
promises.push($.get(url).then(function(data) {return $.post(url)}));
}
// return a promise that resolves only when all the other promises are done
return $.when.apply($, promises);
}
function B() {
// sequence these three operations one after the other
return ($.get(url)
.then(function(data) {return $.post(url + x)})
.then(update_dropdown)
);
}
// run them both, one after the other
A().then(B);
These use the concept that if you return a promise from a .then() handler function, then it will chain multiple async operations together and the master promise is only resolved when all the chained operations are resolved. This is very powerful for sequencing multiple ajax operations and you can even do it for operations in a loop like you have.
Something like this should work
function A {
var xhr = [];
for (var i = 0; i < 5; i++) {
xhr.push( $.get(url) );
}
$.when.apply($, xhr).then(B);
}
function B {
$.get(url).done(function(x) {
$.post(url + x).done(update_dropdown);
});
}
Note the use of an array to keep the promises in, then using $.when with apply() to fire a callback when all the ajax requests in the loop has finished.
Assumptions assumptions ...
Let's assume that :
the url for every get is the same as that for its corresponding post
the urls for each get-post pair should vary
the five get-post pairs in A can occur in parallel and we are not interested in the returned data
First, a utility function :
function getThenPost(url, appendToURL) {
return $.get(url).then(function(x) {
return (appendToURL) ? $.post(url + x) : $.post(url);
});
}
then A and B, both of which call the utility :
function A(urls) {
return $.when.apply(null, urls.map(function(url) {
return getThenPost(url, false);
}));
}
function B(url) {
return getThenPost(url, true);
}
and finally an expression that calls A and B :
A(['/path/0', '/path/1', '/path/2', '/path/3', '/path/4']).then(function() {
B('/path/5');
}).then(update_dropdown);
It should be reasonably simple to adjust this code if assumptions 1 and 2 are incorrect.
If assumption 3 is incorrect then A will require more extensive modification.
We can call our choice function in our way using jquery Deferred Object.
It is very simple let see successfully run example:
<body>
<script
src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
<script type="text/javascript">
// I want to call function in order of f1,f2,f3,f4 every time when i will execute this html page.
promise = f1().then(f2).then(f3).then(f4); // Add handlers to be called when the Deferred object is resolved, rejected, or still in progress.
function f1() {
var d = $.Deferred();
setTimeout(function() {
// our code here....
alert("1");
console.log("1");
d.resolve(); // resolve() :Resolve a Deferred object and call any doneCallbacks with the given args.
},1000); // You set some time for each method.
return d.promise(); //promise(): Return a Deferred’s Promise object.
}
function f2() {
var d = $.Deferred();
setTimeout(function() {
alert("2");
console.log("2");
d.resolve();
},1000);
return d.promise();
}
function f4() {
var d = $.Deferred();
setTimeout(function() {
alert("4");
console.log("4");
d.resolve();
},1000);
return d.promise();
}
function f3() {
var d = $.Deferred();
setTimeout(function() {
alert("3");
console.log("3");
d.resolve();
},1000);
return d.promise();
}
</script>
Javascript without extra work is single threaded. that means functions are not able to be executed simultaneously. but the problem is that the $.get() and $.post() calls are asynchronous. that means they are executed whenever the requested data arrives your client. (first come first serve)
an solution would be to execute function B after all the results ob A arrived, or to hold back all results and handle all data at once then run update_dropdown().

How do promises work in JavaScript?

I just implemented my first function that returns a promise based on another promise in AngularJS, and it worked. But before I decided to just do it, I spent 2 hours reading and trying to understand the concepts behind promises. I thought if I could write a simple piece of code that simulated how promises worked, I would then be able to conceptually understand it instead of being able to use it without really knowing how it works. I couldn't write that code.
So, could someone please illustrate in vanilla JavaScript how promises work?
A promise is basically an object with two methods. One method is for defining what to do, and one is for telling when to do it. It has to be possible to call the two methods in any order, so the object needs to keep track of which one has been called:
var promise = {
isDone: false,
doneHandler: null,
done: function(f) {
if (this.isDone) {
f();
} else {
this.doneHandler = f;
}
},
callDone: function() {
if (this.doneHandler != null) {
this.doneHandler();
} else {
this.isDone = true;
}
}
};
You can define the action first, then trigger it:
promise.done(function(){ alert('done'); });
promise.callDone();
You can trigger the action first, then define it:
promise.callDone();
promise.done(function(){ alert('done'); });
Demo: http://jsfiddle.net/EvN9P/
When you use a promise in an asynchronous function, the function creates the empty promise, keeps a reference to it, and also returns the reference. The code that handles the asynchronous response will trigger the action in the promise, and the code calling the asynchronous function will define the action.
As either of those can happen in any order, the code calling the asynchronous function can hang on to the promise and define the action any time it wants.
For the simplicity to understand about the promises in Javascript.
You can refer below example. Just copy paste in a new php/html file and run.
<!DOCTYPE HTML>
<html>
<head>
<script type="text/javascript">
function test(n){
alert('input:'+n);
var promise = new Promise(function(fulfill, reject) {
/*put your condition here */
if(n) {
fulfill("Inside If! match found");
}
else {
reject(Error("It broke"));
}
});
promise.then(function(result) {
alert(result); // "Inside If! match found"
}, function(err) {
alert(err); // Error: "It broke"
});
}
</script>
</head>
<body>
<input type="button" onclick="test(1);" value="Test"/>
</body>
</html>
Click on Test button,
It will create new promise,
if condition will be true it fulfill the response,
after that promise.then called and based on the fulfill it will print the result.
In case of reject promise.then returns the error message.
Probably the simplest example of promises usage looks like that:
var method1 = (addings = '') => {
return new Promise(resolve => {
console.log('method1' + addings)
resolve(addings + '_adding1');
});
}
var method2 = (addings = '') => {
return new Promise(resolve => {
console.log('method2' + addings)
resolve(addings + '_adding2');
});
}
method1().then(method2).then(method1).then(method2);
// result:
// method1
// method2_adding1
// method1_adding1_adding2
// method2_adding1_adding2_adding1
That's basic of basics. Having it, you can experiment with rejects:
var method1 = (addings = '*') => {
return new Promise((resolve, reject) => {
console.log('method1' + addings)
resolve(addings + '_adding1');
});
}
var method2 = (addings = '*') => {
return new Promise((resolve, reject) => {
console.log('method2' + addings)
reject();
});
}
var errorMethod = () => {
console.log('errorMethod')
}
method1()
.then(method2, errorMethod)
.then(method1, errorMethod)
.then(method2, errorMethod)
.then(method1, errorMethod)
.then(method2, errorMethod);
// result:
// method1*
// method2*_adding1
// errorMethod
// method2*
// errorMethod
// method2*
As we can see, in case of failure error function is fired (which is always the second argument of then) and then next function in chain is fired with no given argument.
For advanced knowledge I invite you here.
please check this simple promise code. this will help you to better understand of promise functionality.
A promise is an object that may produce a single value some time in the future: either a resolved value, or a reason that it’s not resolved. A promise may be in one of 3 possible states: fulfilled, rejected, or pending. Promise users can attach callbacks to handle the fulfilled value or the reason for rejection.
let myPromise = new Promise((resolve, reject)=>{
if(2==2){
resolve("resolved")
}else{
reject("rejected")
}
});
myPromise.then((message)=>{
document.write(`the promise is ${message}`)
}).catch((message)=>{
document.write(`the promise is ${message}`)
})
check this out

Categories

Resources