Reputation: 463
I am having trouble with this code:
// var env_array = ["env1", "env2", "env3", "env4"];
Promise.all(env_array.map(function(env) {
return device_get_env(env).catch(function(err) { return err });
})).then(function(data) {
console.log(data);
data.forEach(function(entry) {
console.log(entry.data.connected);
});
}).catch(function(data) {
console.log(data);
});
function device_get_env(env) {
var env = ...;
var device_id = ...;
return get_token_data(env, 0).then(function(data) {
var url_base = ... ;
return $.ajax({
url: url_base,
method: "GET",
dataType: 'json',
headers: {Authorization: data.token_type + " " + data.access_token}
});
});
}
function get_token_data(env, auth) {
var client_id = env_tokens[env].client_id;
var client_secret = env_tokens[env].client_secret;
var audience = auth == 1 ? "https://" + env + ".xxxx.com/api/v2/" : "yyyy.com";
return $.ajax({
url: "https://" + env + ".xxxx.com/oauth/token",
method: "POST",
data: {
"client_id": client_id,
"client_secret": client_secret,
"audience": audience,
"grant_type": "client_credentials"
},
dataType: 'json'
});
}
Basically I need to iterate over env_array
and find device items in some of my environments.
device_get_env() returns AJAX call, which could be a success/200 or error/404.
Thus my Promises.all won't return unless all promises are resolved.
I've been digging how to overcome this.
Been trying to implement this solution: https://stackoverflow.com/a/30378082/1913289, but I'm having this error here:
TypeError: device_get_env(env).catch is not a function. (In 'device_get_env(env).catch(function(err) {return err} )', 'device_get_env(env).catch' is undefined)
Any way to solve this with my code here?
UPD: implementation suggested by @Bergi
function get_token_data(env, auth) {
var client_id = env_tokens[env].client_id;
var client_secret = env_tokens[env].client_secret;
var audience = auth == 1 ? "https://" + env + ".xxxx.com/api/v2/" : "yyyy.com";
return Promise.resolve(
$.ajax({
url: "https://" + env + ".xxxx.com/oauth/token",
method: "POST",
data: {
"client_id": client_id,
"client_secret": client_secret,
"audience": audience,
"grant_type": "client_credentials"
},
dataType: 'json'
})
)
}
function device_get_env(env) {
var env = ...;
var device_id = ...;
return get_token_data(env, 0).then(function(data) {
var url_base = ... ;
return Promise.resolve(
$.ajax({
url: url_base,
method: "GET",
dataType: 'json',
headers: { Authorization: data.token_type + " " + data.access_token }
})
)
});
}
Promise.all(env_array.map(function(env) {
return device_get_env(env).then(null, function(err) { return err });
})).then(function(data) {
console.log(data);
}).catch(function(data) {
console.log(data);
});
UPD1:
Promise.all(env_array.map(function(env) {
return device_get_env(env).catch(function(err) {return err} );
})).then(function(data) {
console.log(data);
}).catch(function(data) {
console.log(data);
});
FINAL UPD: I used fetch: https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch#Supplying_request_options
to replace my AJAX http requests.
The Promise returned from fetch() won’t reject on HTTP error status even > if the response is an HTTP 404 or 500. Instead, it will resolve normally > (with ok status set to false), and it will only reject on network failure > or if anything prevented the request from completing.
Promise.all example:
Promise.all(env_array.map(function(env) {
return device_get_env(env);
})).then(function(data) {
console.log(data);
}).catch(function(data) {
console.log(data);
});
fetch example:
function get_token_data(env, auth) {
var client_id = env_tokens[tenant].client_id;
var client_secret = env_tokens[env].client_secret;
var audience = auth == 1 ? "https://" + env + ".xxxx.com/api/v2/" : "yyyy.com";
var url_base = "https://" + env + ".xxxx.com/oauth/token";
var myInit = {
method: 'POST',
mode: 'cors',
dataType: 'json',
cache: 'default',
data: {
"client_id": client_id,
"client_secret": client_secret,
"audience": audience,
"grant_type": "client_credentials"
}
};
return fetch(url_base, myInit);
}
Upvotes: 1
Views: 2987
Reputation: 6458
Your first clue that you aren't returning a Promise somewhere in your code is in your error:
TypeError: device_get_env(env).catch is not a function.
The error is telling you that you are trying to call .catch()
on an object that doesn't have a catch()
method on it (even though AJAX objects are technically "thenable", earlier versions of jQuery don't have a catch()
method. So one solution is to upgrade your version of jQuery1.
Your particular problem is that you are not getting the ES6 Promise you expect from the AJAX call in your get_token_data()
function, instead, you are returning a jQuery Promise.
So if you wrap/cast the jQuery promise to a catch()
-able ES6 Promise via Promise.resolve()
in get_token_data()
then you should be on the right track:
function get_token_data(env, auth) {
var client_id = env_tokens[env].client_id;
var client_secret = env_tokens[env].client_secret;
var audience = auth == 1 ? "https://" + env + ".xxxx.com/api/v2/" : "yyyy.com";
var ajaxOptions = {
url: "https://" + env + ".xxxx.com/oauth/token",
method: "POST",
dataType: 'json',
data: {
"client_id": client_id,
"client_secret": client_secret,
"audience": audience,
"grant_type": "client_credentials"
}
};
// here is where the magic happens to cast your
// jQuery Promise into a 'catchable' Promise
return Promise.resolve($.ajax(ajaxOptions));
};
I can't test this code, so you might need to tweak it, but that is the basic idea.
Hope this helps!
1 Thanks to @Bergi for reminding me of this.
Upvotes: 2
Reputation: 664206
Your problem is that device_get_env(env)
returns a jQuery promise, not an ES6 promise. And those don't have a .catch()
method until v3.0…
To overcome this issue, you can either
return Promise.resolve($.ajax(…))
in get_token_data
, or.then(null, function(err) { return err })
instead of .catch(…)
Upvotes: 3