Parse Promises in Cloud Code / Express.js [duplicate] - express

I had a look at the bluebird promise FAQ, in which it mentions that .then(success, fail) is an antipattern. I don't quite understand its explanation as for the try and catch.
What's wrong with the following?
some_promise_call()
.then(function(res) { logger.log(res) }, function(err) { logger.log(err) })
It seems that the example is suggesting the following to be the correct way.
some_promise_call()
.then(function(res) { logger.log(res) })
.catch(function(err) { logger.log(err) })
What's the difference?

What's the difference?
The .then() call will return a promise that will be rejected in case the callback throws an error. This means, when your success logger fails, the error would be passed to the following .catch() callback, but not to the fail callback that goes alongside success.
Here's a control flow diagram:
To express it in synchronous code:
// some_promise_call().then(logger.log, logger.log)
then: {
try {
var results = some_call();
} catch(e) {
logger.log(e);
break then;
} // else
logger.log(results);
}
The second log (which is like the first argument to .then()) will only be executed in the case that no exception happened. The labelled block and the break statement feel a bit odd, this is actually what python has try-except-else for (recommended reading!).
// some_promise_call().then(logger.log).catch(logger.log)
try {
var results = some_call();
logger.log(results);
} catch(e) {
logger.log(e);
}
The catch logger will also handle exceptions from the success logger call.
So much for the difference.
I don't quite understand its explanation as for the try and catch
The argument is that usually, you want to catch errors in every step of the processing and that you shouldn't use it in chains. The expectation is that you only have one final handler which handles all errors - while, when you use the "antipattern", errors in some of the then-callbacks are not handled.
However, this pattern is actually very useful: When you want to handle errors that happened in exactly this step, and you want to do something entirely different when no error happened - i.e. when the error is unrecoverable. Be aware that this is branching your control flow. Of course, this is sometimes desired.
What's wrong with the following?
some_promise_call()
.then(function(res) { logger.log(res) }, function(err) { logger.log(err) })
That you had to repeat your callback. You rather want
some_promise_call()
.catch(function(e) {
return e; // it's OK, we'll just log it
})
.done(function(res) {
logger.log(res);
});
You also might consider using .finally() for this.

The two aren't quite identical. The difference is that the first example won't catch an exception that's thrown in your success handler. So if your method should only ever return resolved promises, as is often the case, you need a trailing catch handler (or yet another then with an empty success parameter). Sure, it may be that your then handler doesn't do anything that might potentially fail, in which case using one 2-parameter then could be fine.
But I believe the point of the text you linked to is that then is mostly useful versus callbacks in its ability to chain a bunch of asynchronous steps, and when you actually do this, the 2-parameter form of then subtly doesn't behave quite as expected, for the above reason. It's particularly counterintuitive when used mid-chain.
As someone who's done a lot of complex async stuff and bumped into corners like this more than I care to admit, I really recommend avoiding this anti-pattern and going with the separate handler approach.

By looking at advantages and disadvantages of both we can make a calculated guess as to which is appropriate for the situation.
These are the two main approaches to implementing promises. Both have it's pluses and minus
Catch Approach
some_promise_call()
.then(function(res) { logger.log(res) })
.catch(function(err) { logger.log(err) })
Advantages
All errors are handled by one catch block.
Even catches any exception in the then block.
Chaining of multiple success callbacks
Disadvantages
In case of chaining it becomes difficult to show different error messages.
Success/Error Approach
some_promise_call()
.then(function success(res) { logger.log(res) },
function error(err) { logger.log(err) })
Advantages
You get fine grained error control.
You can have common error handling function for various categories of errors like db error, 500 error etc.
Disavantages
You will still need another catch if you wish to handler errors thrown by the success callback

Simple explain:
In ES2018
When the catch method is called with argument onRejected, the
following steps are taken:
Let promise be the this value.
Return ? Invoke(promise, "then", « undefined, onRejected »).
that means:
promise.then(f1).catch(f2)
equals
promise.then(f1).then(undefiend, f2)

Using .then().catch() lets you enable Promise Chaining which is required to fulfil a workflow. You may need to read some information from database then you want to pass it to an async API then you want to manipulate the response. You may want to push the response back into the database. Handling all these workflows with your concept is doable but very hard to manage. The better solution will be then().then().then().then().catch() which receives all errors in just once catch and lets you keep the maintainability of the code.

Using then() and catch() helps chain success and failure handler on the promise.catch() works on promise returned by then(). It handles,
If promise was rejected. See #3 in the picture
If error occurred in success handler of then(), between line numbers 4 to 7 below. See #2.a in the picture
(Failure callback on then() does not handle this.)
If error occurred in failure handler of then(), line number 8 below. See #3.b in the picture.
1. let promiseRef: Promise = this. aTimetakingTask (false);
2. promiseRef
3. .then(
4. (result) => {
5. /* successfully, resolved promise.
6. Work on data here */
7. },
8. (error) => console.log(error)
9. )
10. .catch( (e) => {
11. /* successfully, resolved promise.
12. Work on data here */
13. });
Note: Many times, failure handler might not be defined if catch() is
written already.
EDIT: reject() result in invoking catch() only if the error
handler in then() is not defined. Notice #3 in the picture to
the catch(). It is invoked when handler in line# 8 and 9 are not
defined.
It makes sense because promise returned by then() does not have an error if a callback is taking care of it.

Instead of words, good example. Following code (if first promise resolved):
Promise.resolve()
.then
(
() => { throw new Error('Error occurs'); },
err => console.log('This error is caught:', err)
);
is identical to:
Promise.resolve()
.catch
(
err => console.log('This error is caught:', err)
)
.then
(
() => { throw new Error('Error occurs'); }
)
But with rejected first promise, this is not identical:
Promise.reject()
.then
(
() => { throw new Error('Error occurs'); },
err => console.log('This error is caught:', err)
);
Promise.reject()
.catch
(
err => console.log('This error is caught:', err)
)
.then
(
() => { throw new Error('Error occurs'); }
)

Related

Chai expect "not.to.throw" not catching unexpected error

I'm testing a function using Chai's expect ... not.to.throw pattern (v4.3.4):
describe('parseInt', () => {
it('does not throw TypeError', () => {
// foo is not defined, so a ReferenceError is thrown... somewhere?
expect(() => parseInt(foo)).not.to.throw(TypeError);
});
});
The closure throws an error, but I don't see this error anywhere in the output (running mocha). The test passes without the slightest indication of the problem inside the closure.
I expect to at least see the error in the console, even if the tests pass.
This answer says that such errors must be run like so:
// wrapping describe/it are elided
try {
expect(() => parseInt(foo)).not.to.throw(TypeError);
} catch (e) {
expect(e).to.be.a(ReferenceError); // should PASS, and does
}
This passes, but doesn't appear to be testing the second condition. I can flip it and the test still passes:
// wrapping describe/it are elided
try {
expect(() => parseInt(foo)).not.to.throw(TypeError);
} catch (e) {
expect(e).not.to.be.a(ReferenceError); // should FAIL, but does not
}
What am I missing?
Edit
I think the behavior you are observing is actually expected. The original post you referenced may be misleading.
Consider the following test:
// describe/it wrappers have been redacted
expect(()=>parseInt(foo)).to.not.throw(TypeError)
Should this test pass or fail? Intuitively it should pass since the assertion is met: a TypeError was not thrown.
Again for the following test, should 'hello there' be logged to the console?
// describe/it wrappers have been redacted
try {
expect(() => parseInt(foo)).to.not.throw(TypeError);
} catch (e) {
console.log('hello there')
}
If yes, then the statement expect(() => parseInt(foo)).to.not.throw(TypeError), must throw.
And for it to throw, the assertion - not throw a TypeError - must not be met, but we have already established that the assertion is met, and so no exception is thrown.
Therefore, all code in the catch block is unreachable.
This is why the second assertion in your original example is never executed. It will only be reached if the code somehow threw a TypeError and caused the assertion to fail.
Possible solution
For the approach you are taking, I think it could work if there was a way to tell mocha/chai to still go ahead and propagate the error that is thrown by the target function even if the assertion is met. I am unsure of if there is a way to do this, though.
Alternative approach
Alternatively, I think you can get the same (or similar) outcome for the test you have in mind by doing this instead:
// describe/it wrappers have been redacted
const myFunc = () => parseInt(foo)
expect(myFunc).to.not.throw(TypeError)
expect(myFunc).to.throw(ReferenceError)
Here are the assumptions underlying the above test:
You are expecting an error
The error should under no circumstances be a TypeError
The error thrown should always be a ReferenceError.
In case these assumptions do not match what you are currently testing for, or if my alternate approach does not satisfy your needs, kindly let me know!
PS, I used mocha: "^9.1.0" and chai: "^4.3.4" for these tests.

Architecture Nested API async calls

In order to use some online service, I need to call an API three times.
Upload the file
Request an operation
Download the file
I can handle all operations individually but I have hard times to sequence them as they are asynchronous. I wish I can handle all operations in one function call and all I am asking here is some advice to start on the right foot.
I have been playing with promises but got lost in the progress.
function main(){
//Pseudo code
calling async step1
exit if step1 failed
calling async step2
exit if step2 failed
calling async ste3
exit if step3 failed
return OK
}
Thanks in advance.
Since you've given us no real code and no specific information on your APIs, I will offer an answer assuming that the APIs return promises or can be made to return promises. In that case, sequencing and doing error handling is quite simple:
ascync function main() {
let step1Result = await step1();
let step2Result = await step2();
let step3Result = await step3();
return finalValue;
}
// usage
main().then(finalResult => {
console.log(finalResult);
}).catch(err => {
console.log(err);
});
Some things to know:
Because main is declared async, it can use await internal to its implementation.
Because main is delcared async, it will always return a promise
This code assumes that step1(), step2() and step3() return promises that are linked to the completion or error of one or more asynchronous operations.
When the function is executing, as soon as it hits the first await, the function will return an unresolved promise back to the caller.
If any of the await stepX() calls reject (e.g. have an error), that will abort further execution of the function and reject the promise that was previously returned with that specific error. It works analogous to throw err in synchronous programming, but the throw is caught automatically by the async function and turned into a reject for the promise that it already returned.
Your final return value in the function is not actually what is returned because remember, a promise was already returned from the function when it hit the first await. Instead, the value you return becomes the resolved value of that promise that was already returned.
If your API interfaces don't currently return promises, then you can usually find a wrapper that someone has done to create a version that will return promises (since promises are the modern way of working with asynchronous interfaces in Javascript). Or, you can create your own wrapper. In node.js, you can use util.promisify() or you can manually make your own wrapper (just takes a few lines of code).
If you need to catch an error within the function in order to handle it and continue, you can either wrap a given await call in try/catch or use .catch() on the promise and "handle" the error and continue processing, again similar to handling exceptions in synchronous code.
If any of the steps had an error and rejected their promise, then main() will abort and reject similar to throwing an exception in synchronous code.
See also:
How to chain and share prior results with Promises

Why jest expects an anonymous function to catch an error?

I have not comprehended what's the reason behind the fact that expects a curried function when I want to test the output of the error message. If it was going to be a return value a direct call to the function leads to the value to be tested correctly in .toBe
function calculateMedian({numbers}) {
if (Array.isArray(numbers) && numbers.length === 0) {
throw new Error('Cannot calcuate median without any numbers');
}
}
However, if i were to test the following snipped without the anonymous function the test will simply fail. What is the reason behind it?
Passing Test
it('should throw an error when given an empty array', () => {
expect(() =>
calculateMedian({
numbers: [],
}),
).toThrow('Cannot calcuate median without any numbers');
});
Failing Test
it('should throw an error when given an empty array', () => {
expect(calculateMedian({numbers: []})
).toThrow('Cannot calcuate median without any numbers');
});
expect and toThrow are just function calls. So, for the assertion on exception to work, the thing you pass as expect argument needs to allow for execution controlled by the testing framework.
The flow is similar to:
expect() saves the lambda as variable
toThrow() executes the saved variable in a try/catch block and tests the caught exception.
The way you would do it without the toThrow method would be similar to:
try {
calculateMedian({numbers: []};
fail();
} catch (err) {
expect(err.message).toBe('Cannot calcuate median without any numbers')
}
If, instead of passing a lambda/function you simply invoke the function, the error will be thrown before program control gets to the toThrow method. The test will fail because of the thrown error.

handling error from Angular httpClient retryWhen block

I have a pretty simple http call happening. Upon error I want the request to retry 3 times with a three second delay between retries. I have worked out a solution that is close:
return this.http.put<string>(URL,
value).retryWhen(err => {
return err
.delay(3000)
.take(3)
.concat(Observable.throw("error occurred"));
})
.catch(err => this.handleHttpError(err)) ;
The client retries three times like I expect. However, I don't know how to throw the final error in such a way that my error handler (which normally expects an HttpResponse argument) can process the error.
Once I have taken(3) how can I get the final error, and convert it to an HttpResponse to send to my handler? Or am I looking at this the wrong way?
I need to know, at the end of the day, the HttpResponse that accompanied the error(s). When I throw the err from the retryWhen at the concat function that doesn't seem to accomplish it.
I am betting this is a pretty common thing to do, but being newer to Angular 5 and react I think I am just missing the boat.
You can use concatMap to count how many times you've tried to resubscribe and according to that send next or error notifications (this means re-throwing the error in the inner observable that is propagated further).
Observable.throw(42)
.retryWhen(err => err
.do(console.info) // remove, prints 42
.delay(3000)
.concatMap((error, index) => {
if (index === 2) {
return Observable.throw("error occurred"); // or Observable.throw(error);
}
return Observable.of(null);
})
)
// .catch(err => handleHttpError(err))
.subscribe(
v => console.log('next', v), // not called
e => console.log('error handler', e),
);
This prints the following output:
42
42
42
error handler: error occurred
See live demo: https://stackblitz.com/edit/rxjs5-jt5ald
For anyone who runs into this, I was able to capture the httpErrorResponse by slightly changing the return:
first I added a local var
let httpError: HttpErrorResponse = null;
then I modified the return:
return error
.do(err => {if (err instanceof HttpErrorResponse) {httpError = err; }})
.delay(3000)
.take(5)
.concat(Observable.throw(error));
})
this allows me to cache the last http error response. I then look for this in the catch and work accordingly. Seems to be working just fine.

Extjs4.1, Retrieve response message after store sync

How to retrieve response message in failure function?
store.sync({
success : function(){},
failure : function(response, options){
console.log(response.responseText); //it does not work, because there is responseText attr in response
}
});
Response Text is like this,
{"success":false,"message":"Test Error"}
Anybody know, please advice me.
Thanks
[EDIT]
console.log(response);
then,
I'm not sure if you ever figured this out, but the suggestions above I'm pretty sure are wrong. You need to look at the request exception of the store proxy.
Here is some code to call before you do the store sync.
Ext.Ajax.on('requestexception', function (conn, response, options) {
if (response.status != 200) {
var errorData = Ext.JSON.decode(response.responseText);
Ext.Msg.alert('Creating User Failed',errorData.message);
}
});
Sorry for digging this old post up but it just hurt to see the answers above since I just went through the same struggle.
HTH's.
Here's what you need:
store.sync({
success: function(batch) {
Ext.Msg.alert('Success!', 'Changes saved successfully.');
},
failure: function(batch) {
Ext.Msg.alert("Failed", batch.operations[0].request.scope.reader.jsonData["message"]);
}
});
The long and short of it all of these answers are incorrect or inefficient.
Ext.Ajax.on can be used, but you will have to worry about race conditions for requests. Do not use this solution because it can trap you easily. The Ext.Ajax.on might get fired for something other than the sync. See exhibit a.
batch.operations[0].response.responseText can be used too, but this is not reliable way of obtaining the response as the "response" object will not always be populated (It depends on the request and if there are exceptions, 404, 500, success: false, etc.)
Exhibit a
// This picked up my autocomplete comboboxes load - not what I wanted!
Ext.Ajax.on({
requestcomplete: {
fn: callback,
scope: this,
single: true
},
requestexecption: {
fn: callback,
scope: this,
single: true
}
});
Current solution
This still does not have the response I am looking for, but meh.
store.sync({
failure: function (batch, eOpts) {
// 'this' is the Ext.data.proxy.Ajax object
// or whatever proxy you are using
var data = this.getReader().jsonData,
raw_data = this.getReader().rawData;
}
});
I am not sure how this handles my full exception stack of cases, but I will amend my post based on the server-side exceptions I discover (404, 500, etc.)