Reputation: 1905
I am currently using a $.Deferred()
object for posting messages.
When the server returns an error, I am using notify
, and try again until it succeeds or fails X
times.
I want to remove the usage of jQuery, ant move to ES6 related options.
I know how to use Promise()
, but it can either be rejected or resolved, but not both.
Is there a better idea?
The current code:
var def = $.Deferred(),
data = {
iTries: 0,
....
};
$.ajax({
type: "POST",
url: "POST",
data: data,
timeout: 15000,
success: d => def.resolve(d);,
error: function(vSocket, status, error) {
def.notify('error'); // this I want to replace
data.iTries++;
//try again
if (data.iTries < 40) window.setTimeout(function() {
DoAgain(data, def).then(q => def.resolve(q));
}, 9000);
else {
def.reject();
}
}
else {
if (data.iTries < 20) window.setTimeout(function() {
Poll.AjaxPoll(data, def).then(q => def.resolve(q));
}, 30000);
}
}
});
Upvotes: 0
Views: 370
Reputation: 2964
It seems from your code that you are using ES6 (you are using arrow functions). You can follow a recursive approach with es6 arrow functions and promises, it could be something like this:
doAjaxRequest(data) {
fireAPICall(data).then(response => { // fireAPICall is a method that fires the post request and returns the response received from server
if(response.status == 200) { // success (this if statement is optional)
// handle success
let d = response.data;
}
}).catch(error => { // failure
data.iTries++;
if(data.iTries < 40) {
window.setTimeout(() => {doAjaxRequest(data)}, 9000); // try again
} else if(data.iTries < 20) {
window.setTimeout(() => {doAjaxRequest(data)}, 30000); // try again
}
});
}
For the fireAPICall
method, you can use any promise-based http client like axios or Fetch API, here I'm using axios
:
fireAPICall(data) {
return axios.post("url", data);
}
Update: if you want handle both reject/failure
event and notify/progress
events, this will need some server-side collaboration. You could make your server return a 202
status code (or any other more appropriate status code) in case of progress event (not ready yet) and you can handle that in your .then()
callback:
doAjaxRequest(data) {
fireAPICall(data).then(response => { // fireAPICall is a method that fires the post request and returns the response received from server
if(response.status === 202) { // notify/progress event
data.iTries++;
if(data.iTries < 40) {
window.setTimeout(() => {doAjaxRequest(data)}, 9000); // try again
} else if(data.iTries < 20) {
window.setTimeout(() => {doAjaxRequest(data)}, 30000); // try again
} else {
return Promise.reject('poll eneded with no success'); // exceeded maximum number of times for polling, so reject. This will invoke the catch callback method with this error
}
} else { // handle success
let d = response.data;
}
}).catch(error => { // reject/failure for some other reason
// handle error
});
}
Upvotes: 1
Reputation: 1074445
As you say, a promise can only be settled once. (This is also true of jQuery's $.Deferred
, which is [now] mostly promise-like.)
Recurring notifications aren't a use case for promises. Instead, you want some kind of event emitter or publish/subscribe system (there are same extremely small ones for jQuery, such as this one [not an endorsement]), or even just a callback you call with progress updates.
Upvotes: 0