JQuery deferred reject immediately - javascript

When using JQuery.Deferred is it OK to invoke reject() directly? Without having invoked a async function?
Perhaps I want some kind of test in the beginning of my async function. If the test fails I want to reject immediately. See the first if block below.
function doSomethingAsync() {
//Test if the ajax call should be invoked
var testFailed = true;
var dfd = $.Deferred();
//Check if test failed
if (testFailed) {
var asyncResult = {
success: false,
data: 'test failed'
};
//Is this OK usage of reject on the same thread?
dfd.reject(asyncResult);
return dfd.promise();
}
$.get('/api/testapi/get').done(function (data) {
var asyncResult = {
success: true,
data: data
};
dfd.resolve(asyncResult);
}).fail(function (err) {
var asyncResult = {
success: false,
data: err
};
dfd.reject(asyncResult);
});
return dfd.promise();
}

When using JQuery.Deferred is it OK to invoke reject() directly? Without having invoked a async function?
Yes, it's totally OK to return an already rejected promise, and to reject deferreds immediately. You only might need to verify that your callbacks don't rely on asynchronous resolution, which jQuery does not guarantee (in contrast to A+ implementations).
Notice that in your code you should use then instead of manually resolving the deferred:
function doSomethingAsync() {
var testFailed = /* Test if the ajax call should be invoked */;
var dfd = testFailed
? $.Deferred().reject('test failed')
: $.get('/api/testapi/get');
return dfd.then(function (data) {
return {
success: true,
data: data
};
}, function (err) {
return {
success: false,
data: err
};
});
}

You can do it quickly, as your function return a Promise object:
return Promise.reject('test failed');

Related

How to launch 1 by 1 ajax request

I'm having some trouble. I'm trying to execute my ajax function 1 by 1, not all at the same time. I'm using promise but I have no more idea on how to achieve it. Here is my code :
function run_action(action){
if(action == "login"){
return $.ajax({
url: "login.php",
type: "post",
data: {password: password},
beforeSend: function() {
console.log('beforeSend login');
},
success: function (response) {
console.log('Success Login');
},
error: function (request, error) {
console.log('Error Login');
},
})
}
if(action == "register"){
return $.ajax({
url: "register.php",
type: "post",
data: {password: password},
beforeSend: function() {
console.log('beforeSend register');
},
success: function (response) {
console.log('Success Register');
},
error: function (request, error) {
console.log('Error Register');
},
})
}
}
var actions = ['register', 'login'];
services.forEach(checkActions);
function checkActions(item, index) {
if (document.getElementById(item).checked) {
var promise = run_action(item);
promise.success(function (data) {
console.log('Run after');
});
console.log('Run first')
}
}
In this case login and register are both launched at the same time, login doesn't wait for register to finish so he can start processing.
In case you can't properly wait for checkActions from the outside, you could maintain a task queue for that:
let queue = Promise.resolve();
function checkActions(item, index) {
queue = queue
.then(() => run_action(item))
.then(() => {
console.log("Next item was processed", item);
// Your code here
});
// Synchronous code here - This won't execute in order!
}
Currently your code runs through the forEach loop with each action and invokes checkActions with that action, thus firing the request. Array.prototype.forEach executes synchronously (without any kind of check to the promises returned by $.ajax). The following would wait for 'register' to finish before firing 'login':
function checkActions(item) {
if (document.getElementById(item).checked) {
return run_action(item);
}
}
checkActions('register')
.then(data => {
return checkActions('login');
});
I'm not super familiar with jQuery's promise structure, so I used .then, but I believe you can use .success without issue as well.
Unrelated comment, your run_actions function should really be split into two functions (login and register) since they are completely unrelated aside from the fact that they are making requests.
First- its not a good practice to trust a order-based function (AKA - run them by the array order), run your functions according to logic.
For example: if the first function was failed - you dont want to run the next functions in the array.
If you consist to run the functions in array - you can use an async
async function runActions( actionsList ) {
for(const action of actionsList) {
await run_action( action );
}
};
In general - we use the then method to run anther function when specific promise is done. Like so:
promise.then( onSuccess => {
// try to log in
}, onFail => {
// tell the user the signup was failed
});
BTW - you can use the native fetch instade of jQuery ajax, and get simple to use, promise-based way to communicate with your sever.
Like so:
fetch("login.php" , {
method: 'POST', // or 'PUT'
body: {password: password}, // data can be `string` or {object}!
headers:{
'Content-Type': 'application/json'
}
}).then( ... )

Javascript and callbacks and defered. How can I run a function after a google gmail API request completes?

I have built up a javascript file that starts with:
var myApp = function () {
var CLIENT_ID = 'xxxxxxx';
var DISCOVERY_DOCS = ["https://www.googleapis.com/discovery/v1/apis/gmail/v1/rest"];
var SCOPES = 'https://www.googleapis.com/auth/gmail.readonly https://www.googleapis.com/auth/analytics.readonly https://www.googleapis.com/auth/drive.readonly';
var authorizeButton = document.getElementById('authorize-button');
return {
The functions are declared like:
getSent: function(callback) {
var request = gapi.client.gmail.users.messages.list({
'userId': 'me',
'labelIds': 'SENT',
'maxResults': 10
});
request.execute(function(response) {
$.each(response.messages, function() {
var messageRequest = gapi.client.gmail.users.messages.get({
'userId': 'me',
'id': this.id
});
messageRequest.execute(myApp.appendMessageRow);
});
});
},
And then run through a single function that calls others:
myApp.init();
How can I defer a function to be run after my google request function getsent() has been fully completed. I have tried using callbacks to another function and it runs but it runs while the getsent() is still being executed. Can I use the jQuery method defered to run the callback when done?
I have tried:
myApp.getSent(myApp.gMailSyncComplete()); // Runs early
and I tried:
myApp.getSent().done(myApp.gMailSyncComplete()); // no jQuery done defined
Some important errors in your code:
You are creating a function getSent that accepts a callback, but you are not calling the callback at all so it won't get executed ever. You should execute the callback when everything else is done.
You are not waiting for all message requests to be completed. You can use a library like async which has the method map to be able to execute all requests in parallel and wait for all of them to be completed before calling the callback.
With these two things in mind, and using async, this would be an example of the resulting code:
getSent: function (callback) {
var request = gapi.client.gmail.users.messages.list({
'userId': 'me',
'labelIds': 'SENT',
'maxResults': 10
})
request.execute(function (response) {
async.map(response.messages, function (msg, cb) {
var messageRequest = gapi.client.gmail.users.messages.get({
'userId': 'me',
'id': msg.id
})
messageRequest.execute(function (result) {
myApp.appendMessageRow(result)
cb()
})
}, function (err) {
if (err) throw err
callback()
})
})
}
Lastly, when invoking this function, keep in mind that the callback parameter must be a function.
To make things clear, let's translate the code you wrote, myApp.getSent(myApp.gMailSyncComplete()), into an equivalent structure:
var callback = myApp.gMailSyncComplete()
myApp.getSent(callback)
When you do this, you are not passing the function but the result of the function, because you are executing it. That's why it gets executed immediately. The correct way to do this would be the following:
var callback = myApp.gMailSyncComplete
myApp.getSent(callback)
Or, in your one-liner example, myApp.getSent(myApp.gMailSyncComplete)
you can use javascript promise.
function testPromise() {
let p1 = new Promise(
// The resolver function is called with the ability to resolve or
// reject the promise
(resolve, reject) => {
/*your async function*/
}
);
// defined what to do when the promise is resolved with the then() call,
// and what to do when the promise is rejected with the catch() call
p1.then(
// Log the fulfillment value
function(val) {
log.insertAdjacentHTML('beforeend', val +
') Promise fulfilled (<small>Async code terminated</small>)<br/>');
})
.catch(
// Log the rejection reason
(reason) => {
console.log('Handle rejected promise ('+reason+') here.');
});
}
You could use jQuery promise(), check the example below.
getSent: function() {
var request = gapi.client.gmail.users.messages.list({
'userId': 'me',
'labelIds': 'SENT',
'maxResults': 10
});
request.execute(function(response) {
$.each(response.messages, function() {
var messageRequest = gapi.client.gmail.users.messages.get({
'userId': 'me',
'id': this.id
});
messageRequest.execute(myApp.appendMessageRow);
});
});
},
...
$.when( myApp.getSent() ).done(function() {
// do whatever you want in here as callback
});
Inside of your getSent function create a jQuery Deferred object and return a promise. Then after request.execute has finished you can call resolve/reject. I created a small snippet to show example. Maybe you can modify to fit your needs
$(document).ready(function () {
var i =0;
function getText() {
var deferred = $.Deferred();
setTimeout(function () {
i++;
deferred.resolve("text " + i);
}, 3000);
return deferred.promise();
}
getText().then(function (value) {
console.log(value);
}).then(function () {
getText().then(function (value2) {
console.log(value2);
});
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

How to syncronize order of chained jQuery promised

I'm chaining 3 ajax requests with to a RESTful endpoint:
PUT some data (return {} and OK)
GET the data I just put
show data
I've set up a chain of promises using .then(). But the request does not happen in the expected order (1,2,3) but rather (2,1) and starting with a OPTIONSrequest.
Why are they not happening in the expected order?
How can I ensure the correct sequential order?
var _id = x;
function doReqs() {
putData(_id, data)
.then(getData(_id))
.then(showData);
}
// returns empty object {}
function putData(id, data) {
return $.ajax({
method: 'PUT',
url: http://xxx,
contentType: 'application/json'
});
}
// returns JSON {"data": {"xx": "xx}}
function getData(id) {
return $.ajax({
method: 'GET',
url: http://xxx
});
}
function showData(data) {
console.log(data);
}
In this code:
function doReqs() {
putData(_id, data)
.then(getData(_id))
.then(showData);
}
The .then(getData(_id)) part is just wrong. It's wrong for two reasons.
.then() is supposed to be passed a function reference. When you pass getData(_id), you are executing that function immediately and passing the return value from that function (which is a jqXHR object) to .then(). That's not what you're supposed to pass to .then().
Because you're executing getData(_id) IMMEDIATELY, it will not execute properly in the promise chain sequence.
Remember, any time you pass a func() with the parens after it as an argument, it executes that function immediately and passes it's return value as the argument. That is NOT what you want with .then() for the above reasons.
If you're trying to control what is being passed to getData(), then you can either make sure the right thing is returned from putData() because that's what will be passed to getData() or you can make a stub function that will pass the right thing:
function doReqs() {
putData(_id, data)
.then(function() {
return getData(_id);
})
.then(showData);
}
Or, you could do it this way:
function doReqs() {
putData(_id, data)
.then(getData.bind(null, _id))
.then(showData);
}
Or, since the resolved value of putData() is what will be passed as an argument to the next step in the promise chain (which is getData), you could do this:
function putData(id, data) {
return $.ajax({
method: 'PUT',
url: http://xxx,
contentType: 'application/json'
}).then(function() {
// make sure putData passes the id to the next step in the chain
return id;
});
}
function doReqs(id) {
putData(id, data)
.then(getData)
.then(showData);
}
Here's a working example of chaining in action:
function delay(t, val) {
return new Promise(function(resolve) {
setTimeout(resolve.bind(null, val), t);
});
}
function first(arg) {
console.log("running first..., arg = ", arg);
return delay(500, 10);
}
function second(arg) {
console.log("running second..., arg = ", arg);
return delay(100, 100);
}
function third(arg) {
console.log("running third..., arg = ", arg);
}
first(1).then(second).then(third);

Resolving/rejecting promises within $http get not working.

I am trying to reject a deferred object within a $http.get call but it is not being properly rejected. The errorcallback is not being called, and I just can't figure out why.
Here is basically what I have:
var promise = this.SomeAsyncCall(this.$.SomeID)
.then(
function ()
{
service.SendAsyncDownloadReqeuest(someOtherID);
},
this.ErrorHandler.HandleError)
.then(this._DownloadInitiated, this.ErrorHandler.HandleError);
promise["finally"](this._DownloadRequestFinished);
And here is the service.SendAsyncDownloadRequest:
var SendAsyncDownloadReqeuest = function (ID)
{
var url = "someUrl?ID=" + customerID;
var navigator = self.$window.navigator;
var window = self.$window;
var deferred = self.$q.defer();
self.$http.get(url, { responseType: 'arraybuffer' })
.success( function(data, status, headers) {
var success = false;
//Initiate download via blob. Set success
success ? deferred.resolve() : deferred.reject();
})
.error(function (data, status)
{
var error =
{
//Some error properties
}
deferred.reject(error);
});
return deferred.promise;
};
When I test this by returning a 500 status code from the server, it reaches the .error block of the http get call and completes the reject line, but the ErrorHandler's HandleError method is not reached. The HandleError method is correct since it works with errorcallbacks for promises rejected in anything that's not $http.get.
You're never passing the promise from service.SendAsyncDownloadReqeuest(someOtherID); back to your HandleError function. You need to change your code to this:
var promise = this.SomeAsyncCall(this.$.SomeID)
.then(
function ()
{
return service.SendAsyncDownloadReqeuest(someOtherID);
},
this.ErrorHandler.HandleError)
.then(this._DownloadInitiated, this.ErrorHandler.HandleError);
promise["finally"](this._DownloadRequestFinished);
If you want to be a little clearer you could change it to this:
var promise = this.SomeAsyncCall(this.$.SomeID)
.then(function () {
service.SendAsyncDownloadReqeuest(someOtherID).then(
this._DownloadInitiated,
this.ErrorHandler.HandleError);
},
this.ErrorHandler.HandleError);
promise["finally"](this._DownloadRequestFinished);
Don't use the success method either way.Both methods have been deprecated.
The $http legacy promise methods success and error have been
deprecated. Use the standard then method instead. If
$httpProvider.useLegacyPromiseExtensions is set to false then these
methods will throw $http/legacy error.
Here is the shortcut method
$http.post('/someUrl', data, config).then(successCallback, errorCallback);
Here is a longer GET method sample
$http({
method: 'GET',
url: '/someUrl'
}).then(function successCallback(response) {
// this callback will be called asynchronously
// when the response is available
}, function errorCallback(response) {
// called asynchronously if an error occurs
// or server returns response with an error status.
});
Official Documentation

AngularJs - defer resolve object

i've a function that return a boolean according to http.get call.
function checkValue (value) {
var defer = $q.defer();
var request = $http({
method: "get",
url: "someurl"
});
request.success(function (data) {
defer.resolve(data.response);
});
return defer.promise;
}
The problem is that return value is an object like this:
d {$$state: Object}
$$state: Object
status: 1
value: true
__proto__: Object
__proto__: d
How could i resolve it?
Yes, your function is returning a Promise object. The $$state property belongs to the promise object and is used by Angular internally (as suggested by $$ prefix) and therefore not to be used by developers using Angular. More interesting is that promise object has a "then" method which can be used to attach handlers that are called when the promise gets resolved. Promise gets resolved when the defer object related to the promise is resolved.
So, you could use your code as
checkValue.then(function (data) {
// This is called when the XHR response comes in and
// defer.resolve() is called in the checkValue function.
});
But, there is a better approach to this. Using promise chaining.
Which essentially removes the need to create a new defer object.
function checkValue (value) {
return $http({
method: "get",
url: "someurl"
}).then(function (data) {
return data.response;
});
}
Explaining everything about how Promises work is may be too much for this post. There are already awesome works done on that.
But, basically, $http already returns a promise. So you can just use this promise instead of creating a new one. The end usage of the function remains exactly the same as the snippet above.
BTW, .success() handlers are deprecated. So better start using .then() on your apps already.
Since you are using Promise, you need to use .then callback in order to get response or error:
function checkValue (value) {
var defer = $q.defer();
var request = $http({
method: "get",
url: "someurl"
});
request.success(function (data) {
defer.resolve(data.response);
});
return defer.promise;
}
var promise = checkValue('Hello World');
promise.then(function(response) {
//success
console.log(response);
}, function(reason) {
//failed
console.log(reason);
});
then(successCallback, errorCallback, notifyCallback) – regardless of
when the promise was or will be resolved or rejected, then calls one
of the success or error callbacks asynchronously as soon as the result
is available. The callbacks are called with a single argument: the
result or rejection reason. Additionally, the notify callback may be
called zero or more times to provide a progress indication, before the
promise is resolved or rejected.
But the optimized approach would be using $http's inbuilt promise instead of creating a new one.
var request = $http({
method: 'GET',
url: '/someUrl'
});
request.then(function successCallback(response) {
// this callback will be called asynchronously
// when the response is available
}, function errorCallback(response) {
// called asynchronously if an error occurs
// or server returns response with an error status.
});
You should try this,
function checkValue (value) {
return $q(resolve, reject) {
$http({
method: "get",
url: "someurl"
}).success(function (data) {
resolve(data.response);
}).then (function (error) {
reject(error);
});
}
}
This will resolve your data

Categories