So I have multiple asynchronous HTTP requests in my pure JS app, but while they load they block the effective work with the app. I want to show a loading indicator for that, I have no idea how I can do it with asynchronous requests.
What I tried.
I checked how many requests I fired in an array while these are not done I showed a loading indicator, but because these are asynchronous after the first set was done there came in another set, because of dependencies to each other.
Is there something to solve this problem?
Lets assume you have code like so:
function doAjax(params, callback) {
// ...
callback(ajaxResponse, error);
}
function doRequests() {
doAjax(params, (success, error) => {
if(error) console.error(error);
console.log(success);
});
doAjax(params2, (success, error) => /* ... */);
// ...
}
You can easily rewrite that into Promises:
function doAjax(params) {
return new Promise((resolve, reject) => {
// ...
if(error) reject(error);
else resolve(ajaxResponse;
});
}
function doRequests() {
showLoader();
Promise.all(doAjax(params), doAjax(params2), /* ... */)
.then((results) => {
console.log(results);
hideLoader();
})
.catch(error => {
console.error(error);
hideLoader();
});
}
Related
On the way of learning the concepts of asynchronous JavaScript, I got struggled with the idea behind the situation when they can be chained. As an example consider the following situation: a webhook calls a cloud function and as a requirement there is set a time interval by which the cloud function should response to the webhook. In the cloud function is called an operation for fetching some data from a database, which can be short- or long-running task. For this reason we may want to return a promise to the webhook just to "register" a future activity and later provide results from it e.g.:
async function main () {
return new Promise ((resolve, reject) => {
try {
db.getSomeData().then(data=> {
resolve({ result: data});
});
} catch (err) {
reject({ error: err.message });
}
});
}
Another way is to use async/await instead of a promise for fetching the data, e.g.:
async function main () {
return new Promise (async (resolve, reject) => {
try {
const data = await db.getSomeData();
resolve({ result: data });
} catch (err) {
reject({ error: err.message });
}
});
}
(The code is a pseudo-code and therefore all checks on the returned types are not considered as important.)
Does the await block the code in the second example and prevent returning of the promise?
async functions always return a Promise. It is up to the function caller to determine how to handle it: either by chaining with then/catch or using await. In your example, there is no need to create and return a new Promise.
You could do something like this for example:
async function main () {
try {
const data = await db.getSomeData()
return {result: data}
} catch (err) {
return {error: err.message}
}
}
// On some other part of the code, you could handle this function
// in one of the following ways:
//
// 1.
// Chaining the Promise with `then/catch`.
main()
.then((result) => console.log(result)) // {result: data}
.catch((err) => console.log(err)) // {error: err.message}
// 2.
// Using await (provided we are working inside an asyn function)
try {
const result = await main()
console.log(result) // {result: data}
} catch (err) {
console.log(err) // {error: err.message}
}
Try to avoid combining both methods of handling asynchronous operations as a best practice.
I'm using the JavaScript Promise object with a then(), catch().
The console.log in the catch() method always runs, regardless of the response from the API ("STATUS_SUCCESS" or "STATUS_FAILED").
Is this normal behaviour in promises or is there a way to only hit the catch() method if the response has failed?
Updated with live example:
sendAccountDataToBackend(response) {
const { formData } = response;
const requestObj = {
url: 'http://localhost:3000/api/validate',
data: {
firstname: 'dummy_firstname',
lastname: 'dummy_lastname',
email: 'dummyemail'
}
};
let p = new Promise((resolve, reject) => {
account.Utils.globalAjaxRequest(requestObj, (success) => {
if(success.status === 'STATUS_SUCCESS') {
resolve();
console.log('resolved: ', p)
} else {
reject();
console.log('rejected: ', p);
}
});
})
p.then(() => {
console.log('Then: ', response);
}).catch(() => {
console.log('catch:', response);
})
}
You can find the exact cause of the thrown error by printing it.
Change your catch handler to look like this:
catch((e) => {
console.log('Catch', e);
})
In addition to "Catch" you will see a description of the error in the console.
I figured out what was causing the catch to fire thanks to #pfcodes suggestion. I was calling a function within the then() block which was failing. Once removed, it stayed inside then(). Silly mistake that was over looked! Thanks for your suggestions.
Regarding the question:
Is this normal behaviour in promises or is there a way to only hit the catch() method if the response has failed?
It is easy to demonstrate that the catch is only entered when the reject call is made.
function testPromise(shouldReject)
{
return new Promise((resolve, reject) => {
setTimeout(function(){
if(shouldReject) reject();
else resolve();
},1000);
});
}
function handlePromise(p, name){
p.then(() => {
console.log(name, 'Then');
}).catch(() => {
console.log(name, 'Catch');
})
}
var rejectPromise = testPromise(true);
var resolvePromise = testPromise(false);
handlePromise(rejectPromise,"reject");
handlePromise(resolvePromise,"resolve");
So, what this means is that in your code, for whatever reason (probably badly handled asynchronous ajax call) you're entering the else block.
Regarding your update, I would say that success.status is returning something other than "STATUS_SUCCESS" for the reasons demonstrated by the code above.
Try adding console.log(success) inside the ajax callback.
account.Utils.globalAjaxRequest(requestObj, (success) => {
console.log(success);
....
(This is my first ever contact with Javascript. ...)
Hi, I have to write a rest api with Express, which is no problem due to the huge amount of examples everywhere.
Though, within a rest request I've to contact another tcp server (for modbus). So, within such a request I've to wait for the connect/ready event from socket.connect(). What's a proper way to do that?
What I came up with is encapsulating the socket.connect() in a Promise. The stripped code looks like:
function get_holding() {
const socket = new net.Socket();
const client = new modbus.client.TCP(socket); /* = require('jsmodbus') */
return new Promise(function (resolve, reject) {
// fulfill the Promise, proceed in the chain
socket.on('ready', function () { resolve(); });
// close connection after receiving the response
socket.on('data', function () { socket.end(); });
socket.on('error', function (error) { reject(error); });
socket.connect(/* ip and port */);
})
.then(function () {
// could be above in socket.on('ready', ...),
// but splitting looks better
return client.readHoldingRegisters(0, 2);
})
.then(function (response) {
// process response (code stripped)
return /* processed values */;
})
.catch(function (error) {
throw error;
});
}
function controller_get_holding(req, res) {
get_holding()
.then(function (values) {
res.json(values);
})
.catch(function (error) {
res.send(require('util').inspect(arguments, {depth: null}));
});
}
...
app.route('/holding')
.get(controller_get_holding);
Is that the way to go?
Just found promise-socket, which is all I need.
I have written a general .js crud object which holds all the methods used to communicate with the server. However I'd like to avoid the repetition of .then and .catch and I would like to abstract that functionality in an external method.
Not sure if what I'm trying to achieve is even possible.
My code below:
all(url, success, fail){
return new Promise((resolve,reject) => {
_get(url)
.then((response) => {
if (response.status == 200) {
success.call(this,response);
return resolve();
}
})
.catch((error) => {
fail.call(this, error);
reject(error);
});
});}, submit, update .....
Wonderland desired result:
all(url, success, fail){
return new Promise((resolve, reject) => {
_get(url).handle(args);
});
}
Just avoid the Promise constructor antipattern and callbacks, and you'll be good!
function all(url) {
return _get(url).then((response) => {
if (response.status == 200) {
return response;
}
// most likely you want to `throw` an error here?
});
}
I am trying to load same image but with different resolution, one by one, with 1.png first and then 2.png and then 3.png, with help of promises, but when i run the code, it loads only 3.png image, what am i doing wrong?
function loadi(srce){
if(srce!='3.png'){
$img1.attr('src',srce).on('load',function(){
return loadImag();
});
}
else{
$img1.attr('src',srce).on('load',function(){
console.log("Load successful");
});
}
}
function loadImag(){
return new Promise(function(fulfill,reject){
fulfill();
});
}
loadImag()
.then(loadi('1.png'),null)
.then(loadi('2.png'),null)
.then(loadi('3.png'),null);
New code after 1st suggestion, still facing the same issue, only one image being loaded as seen in chrome dev tools
function loadi(srce){
return loadImage(srce);
}
function loadImage(src) {
return new Promise(function(resolve, reject) {
$img1.attr('src',src).on('load',function(error){
resolve();
});
// Run image loading logic here
// Call resolve() when loading complete, or reject() when fails.
});
}
loadImage('1.png')
.then(loadi('2.png'))
.then(loadi('3.png'))
.then(function() {
console.log('Load successful!');
}) // Not in loadImage().
.catch(function(err) {
console.log("Error");/* Handle potential errors */
});
Few things wrong with your code:
loadi does not return a Promise. Returning from a callback doesn't work as expected.
loadImag can basically be replaced with Promise.resolve().
.then() is expecting a function, you're passing the result of the function.
Your code should look like this:
function loadImage(src) {
return new Promise(function(resolve, reject) {
// Run image loading logic here
// Call resolve() when loading complete, or reject() when fails.
)};
}
loadImage('1.png')
.then(function() { return loadImage('2.png'); })
.then(function() { return loadImage('3.png'); })
.then(function() { console.log('Load successful!'); }) // Not in loadImage().
.catch(function(err) { /* Handle potential errors */ });