Response terminates before the result could be collected from the promise - javascript

In the following snippet, lineReader listens to an event line. When a line event is received, it calls da on Parser which returns a Promise
lineReader.on('line',(line) => {
Parser.da(line).then((info) => {
});
});
lineReader.on('close',() => {
req.end();
});
Parser.da = function(line) {
return new Promise((resolve,reject) => {
geo.getLocation().then((r) => {
console.log(r); return resolve(r);
});
});
}
da function in return calls a function which also operates on Promise. What happens is that I can never see the output from geo.getLocation and readLine.on('close') gets called.
What should be the way to handle this situation?

You are not resolving the promise. When you get the result from geo service you need to resolve the data.
Take a look this
Parser.da = function(line) {
return new Promise((resolve,reject) => {
geo.getLocation().then((r) => {
console.log(r);
resolve(r);
});
});
}

Why do you not just return the Promise from geo.geoLocation() instead of wrapping it into another promise? Like this:
Parser.da = function(line) {
return geo.geoLocation();
}
Or you might want to chain "then"'s instead. Although this is synchronous
Parser.da = function(line) {
return geo.geoLocation().then(function (r) {
console.log(r);
return r; // return r to chain it to the next ".then"
});
}
One possible problem might be that a promise is asynchronous so the lineReader.on("line"); event is closed before the promise can be executed because the event is synchronous. And then the lineReader.on("close"); is executed before the promise is resolved.
Also you should always have a "catch" in your promise so you can see if there are any errors. Like this:
lineReader.on('line',(line) => {
Parser.da(line).then((info) => {
// ...do code here
}, console.error); // errors will be outputted to console
});

Related

Jest tests of Promises

I need to write a Jest test for a function using Promises, which is working perfectly in the browser.
My code is as follows: a JQuery AJAX call is done, which returns a promise; when this promise is resolved, I call another function, which is also using another Promises internally!
So the code of my Jest test is globally like this:
function post(url) {
return $.ajax(url).then((result) => {
resolve(result);
});
}
function showAlert(message) {
return new Promise((resolve, reject) => {
require('anotherPackage').then(() => { // require returns a Promise
anotherPackage.showAlert(message); // will result in DOM update
}).then(resolve, reject);
});
}
function handleResponse(result) {
const promises = [];
...
promises.push(showAlert(message));
...
return Promise.all(promises);
}
test("Promises test", () => {
let response = null,
url = 'http://example.com/result.json';
return post(url).then([result, status, request] => {
response = parseResponse(result);
}).then(() => {
return handleResponse(response).then(() => {
return $('.alert').length;
}).then(value => {
expect(value).toBe(1); // doesn't work, value is 0 !!!
});
});
});
The handleResponse function is using AJAX request response, and in this use case, the function is calling another function which is using a promise internally which, when resolved, is creating an alert inside the DOM.
Actually, the test given as example doesn't work, because the expect call is done before the inner handleResponse promise is "completely resolved"!
So my question is: how can I handle this use case with Jest?
Best regards,
Thierry

Why is my Promise always hitting the catch() method?

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);
....

JS Promise doesn't chain while working chrome.storage.sync

I'm trying to make a promise chaining, but somehow the asynchronous calling using chrome.storage.sync.get always return later. Here's a correct order I thought it should be:
Create an element and append to body
Call chrome.storage.sync
Based on 2) result, trigger some event on element created in 1)
I've already tried to put new Promise in 2) step, but no successful.
The console.log always return in a wrong order. Something like:
// insertChecbox done
// start promise chrome.storage.sync
// undefined
// result asnyc: ...
Here's my attempt:
const pr = new Promise(resolve => {
this.createCheckbox();
console.log('insertChecbox done')
resolve();
});
pr
.then( resolve => {
console.log("start promise chrome.storage.sync");
return new Promise( resolve => {
return resolve(chrome.storage.sync.get(["code", "isAutocheck"], result => {
console.log('result async: ', result );
return result
}));
});
})
.then( result => {
console.log(result);
console.log('This always run before the `chrome.storage.sync` finishes loading`)
if (result.isAutocheck) {
const domCheckbox = this.getCheckboxElement();
domCheckbox && domCheckbox.click();
}
});
I wanted to separate the result of chrome.storage.sync because I need to work on other stuff, not making this callback too complex
Thanks for noticing this question, I've found an solution by changing a bit in my first .then, by explicitly resolving the result of chrome.storage.sync.get, not the whole thing.
pr
.then( () => {
return new Promise( resolve => {
return chrome.storage.sync.get(["code", "isAutocheck"], result => {
console.log('result async: ', result );
return resolve(result)
});
});
})
.then(...);

Am I chaining Promises correctly or committing a sin?

I have not worked with Javascript in a long time, so now promises are a new concept to me. I have some operations requiring more than one asynchronous call but which I want to treat as a transaction where steps do not execute if the step before failed. Currently I chain promises by nesting and I want to return a promise to the caller.
After reading the chaining section of Mozilla's Using Promises guide, I'm not sure if what I'm doing is correct or equivalent to the "callback pyramid of doom".
Is there a cleaner way to do this (besides chaining with a guard check in each then)? Am I right in my belief that in Mozilla's example it will execute each chained then even when there is an error?
myfunction(key) => {
return new Promise((outerResolve, outerReject) => {
return new Promise((resolve, reject) => {
let item = cache.get(key);
if (item) {
resolve(item);
} else {
//we didnt have the row cached, load it from store
chrome.storage.sync.get(key, function (result) {
chrome.runtime.lastError
? reject({ error: chrome.runtime.lastError.message })
: resolve(result);
});
}
}).then((resolve) => {
//Now the inner most item is resolved, we are working in the 'outer' shell
if (resolve.error) {
outerReject(resolve);
} else {
//No error, continue
new Promise((resolve, reject) => {
chrome.storage.sync.get(keyBasedOnPreviousData, function (result) {
chrome.runtime.lastError
? reject({ error: chrome.runtime.lastError.message })
: resolve(result);
});
}).then((resolve) => {
//finally return the result to the caller
if (resolve.error) {
outerReject(resolve);
} else {
outerResolve(resolve);
}
});
}
});
});
}
Subsequent then statements are not executed (until a catch) when an exception is thrown. Also, .then returns a Promise, so you don't need to create an additional, outer Promise.
Try this example:
var p = new Promise((resolve, reject) => {
console.log('first promise, resolves');
resolve();
})
.then(() => {
throw new Error('Something failed');
})
.then(() => {
console.log('then after the error');
return('result');
});
p.then(res => console.log('success: ' + res), err => console.log('error: ' + err));
You will not see "then after the error" in the console, because that happens after an exception is thrown. But if you comment the throw statement, you will get the result you expect in the Promise.
I am not sure I understand your example entirely, but I think it could be simplified like this:
myfunction(key) => {
return new Promise((resolve, reject) => {
let item = cache.get(key);
if (item) {
resolve(item);
} else {
//we didnt have the row cached, load it from store
chrome.storage.sync.get(key, function (result) {
chrome.runtime.lastError
? throw new Error(chrome.runtime.lastError.message)
: resolve(result);
});
}
}).then((previousData) => {
// keyBasedOnPreviousData is calculated based on previousData
chrome.storage.sync.get(keyBasedOnPreviousData, function (result) {
chrome.runtime.lastError
? throw new Error(chrome.runtime.lastError.message)
: return result;
});
});
}
It's a bit of a mess. This is my attempt at rewriting. A good thing to try to avoid is new Promise().
function chromeStorageGet(key) {
return new Promise( (res, rej) => {
chrome.storage.sync.get(key, result => {
if (chrome.runtime.lastError) {
rej(new Error(chrome.runtime.lastError.message))
} else {
res(result)
}
});
});
});
function myfunction(key) {
const item = cache.get(key) ? Promise.resolve(cache.get(key)) : chromeStorageGet(key);
return item.then( cacheResult => {
return chromeStorageGet(keyBasedOnPreviousData);
});
}
Why avoid new Promise()?
The reason for this is that you want to do every step with then(). If any error happened in any of the promises, every promise in the chain will fail and any subsequent then() will not get executed until there is a catch() handler.
Lots of promise based-code requires no error handlers, because promise-based functions always return promises and exceptions should flow all the back to the caller until there is something useful to be done with error handling.
Note that the exceptions to these 2 rules are in my chromeStorageGet function. A few notes here:
new Promise can be a quick and easy way to convert callback code to promise code.
It's usually a good idea to just create a little conversion layer for this callback-based code. If you need chrome.storage.sync in other places, maybe create a little utility that promisifies all its functions.
If there is only 1 'flow', you can just use a series of then() to complete the process, but sometimes you need to conditionally do other things. Just splitting up these complicated operations in a number of different functions can really help here.
But this:
const result = condition ? Promise.resolve() : Promise.reject();
Is almost always preferred to:
const result = new Promise( (res, rej) => {
if (condition) {
res();
} else {
rej();
}
}

Promises not going in order of the "then()"s? (nodejs)

Why does the then() where it says console.log('THIS COMES BEFORE THE WRITING AND EXTRACTING'); statement come before the writing and extracting to PDFs? I'm new to Promises, so I am a bit confused by this. I want that then() statement to happen AFTER the writing and parsing happens.
function writeToPDF(data, fileName) {
return new Promise((resolve, reject) => {
data.pipe(fs.createWriteStream(fileName), err => {
reject();
});
data.on('end', () => {
resolve();
})
});
}
​
function extractPDF(pdf) {
return new Promise((resolve, reject) => {
extract(pdf, {splitPages: false}, (err, text) => {
if (err) {
console.log(err);
} else {
resolve(text);
}
});
});
}
​
request(link).then((success, failure) => {
let fileName = './name-' + Date.now() + '.pdf';
writeToPDF(data, fileName).then(() => {
extractPDF(fileName).then((text) => {
arrayOfDocuments.push(text);
})
}, () => {
//handle error
});
}).then(() => {
console.log('THIS COMES BEFORE THE WRITING AND EXTRACTING');
});
You are nesting your then values and actually have two different then routes — for lack of a better term.
So far as the javascript is concerned, once the first then is resolved in your request method, it can move on to the next then. Here, once writeToPdf is resolved, that part of the promise chain then moves on to the console.log statement since the previous promise at that level has been resolved. That make sense?
The request(link).then(...) block comprises an outer promise chain and two levels of nested promise chain.
If you write a fat-arrow function with a {block}, returns are not explicit, therefore :
neither of the promises derived from writeToPDF() or extractPDF() is returned,
the outer promise chain is not informed of the existence of inner promises or their settlement,
console.log('THIS COMES BEFORE ...') relies solely on the fulfillment of the promise returned by request(link), and is guaranteed to occur after PDF stuff commences but before it completes.
request(link).then((success, failure) => {
let fileName = './name-' + Date.now() + '.pdf';
return writeToPDF(data, fileName).then(() => {
//^^^^^^
return extractPDF(fileName).then((text) => {
// ^^^^^^
arrayOfDocuments.push(text);
})
}, () => {
//handle error
});
}).then(() => {
console.log('THIS COMES BEFORE THE WRITING AND EXTRACTING');
});

Categories

Resources