I've the following promise which work well
troces.run(value, "../logs/env.txt")
.then(function (data) {
console.log(data);
return updadeUser(val, arg, args[1])
// Now here I need to add new method updateAddress(host,port,addr)
}).catch(function (err) {
console.error(err);
});
Now I need to add additional method call inside the the first .then
that the update user and the updateAddress will work together
My question are
assume that updateUser will need to start 10 ms after the update
address How is it recommended to do so?
in aspects of error handling if one of the process failed (send error message ) I Need to exit (process.exit(1);)
Use .all:
troces.run(value, "../logs/env.txt")
.then(data => {
console.log(data);
return Promise.all([updadeUser(val, arg, args[1]),
updateAddress(host,port,addr)]);
}); // no need to add catches bluebird will log errors automatically
If you really need the 10ms delay, you can do:
troces.run(value, "../logs/env.txt")
.then(data => {
console.log(data);
return Promise.all([updadeUser(val, arg, args[1]),
Promise.delay(10).then(x => updateAddress(host,port,addr))]);
}); // no need to add catches bluebird will log errors automatically
Although I suspect that you really just want updateUser to happen before updateAddress which can be easily solved with:
troces.run(value, "../logs/env.txt")
.then(data => {
console.log(data);
return updadeUser(val, arg, args[1]).then(_ => updateAddress(host,port,addr));
}); // no need to add catches bluebird will log errors automatically
If you need to exit on promise error, you can do:
process.on("unhandledRejection", () => process.exit(1));
Although I warmly recommend you create meaningful error messages, just a non-zero process exit code is hard to debug.
Related
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'); }
)
I'm integrating with a 3rd party script and have come across a scenario which I don't know how to test properly.
The 3rd party script adds an object to the window with a few methods. The second argument of the create method is a callback function which returns a promise that is either rejected or resolved.
I need to be able to mock that second argument with either a reject or resolved status so that my unit test can cover whether the UI is updated with either the error or success message.
How can I mock this function and the callback function with the proper response?
thirdpartyform.create(options, (err, message) => {
return new Promise((resolve, reject) => {
if (err) {
reject(err.reason)
} else {
resolve(message)
}
})
.then(message => {
setState(message)
})
.catch((err) => {
setState(err)
})
})
Below is my current attempt at mocking the function (against the window object) which is not working. It does not properly set the rejected value or resolved value :(
create: jest.fn((options, callback) => callback(jest.fn().mockRejectedValue(FORM_TIMEOUT)))
Any help would be greatly appreciated
create is callback-based and is unaware of promises, so a mock shouldn't involve promises either.
Given that thirdpartyform.create is a spy that has been previously set up with jest.mock, jest.spyOn, etc, a mock for successful response:
thirdpartyform.create.mockImplementation((options, cb) => cb(null, 'message'))
A mock for unsuccessful response:
thirdpartyform.create.mockImplementation((options, cb) => cb({ reason: 'error' }))
I'm trying to improve the use of promises in some code that retrieves REST resources. I have a number of REST calls that make the perform the same sequence of actions:
Fetch the config resource from the server if it hasn't been obtained previously
Dispatch a flux action indicating the start of the request
Send a request for the actual resource
Parse the JSON in the response
Dispatch a flux action indicating success with the parsed data.
The code I currently use to do this is below.
getThingsFromServer() {
return getConfigIfNeeded().then(() => {
dispatchStartOfRequestAction();
return window.fetch(`${store.baseURL}/resource`)
.then((response) => {
if(response.ok) {
return response.json();
} else {
return Promise.reject(new Error(`${response.status} ${response.statusText}`));
}
}, (error) => {
return Promise.reject(new Error(`Network error: ${error.message}`));
})
.then((data) => {
dispatchSuccessAction(data);
}, (error) => {
return Promise.reject(new Error(`JSON parse error: ${error.message}`));
})
.catch((error) => {
dispatchFailureAction(error)
});
});
}
There are a number of error conditions I would like to be able to handle individually, after which I want to dispatch a failure action (which is done in the catch()).
At the moment, if one of the individual then() error handlers gets called, every subsequent then() error handler is also called before finally calling the catch(). I want just one individual handler and the catch to be called.
I could dispense with handling each error individually and use a single catch at the end of it all but various sources both support and vilify the practice of handling all these different errors in the same way at the end of a promise chain. Is there a "right" answer to this beyond personal opinion?
if one of the individual then() error handlers gets called, every subsequent then() error handler is also called
Yes, if you throw (or return a rejected promise) from then handler, the promise will get rejected and subsequent error handlers will get called. There's really no way around this. To differentiate the errors, you'll have to nest (see also here).
In your case, you'll want to use
dispatchStartOfRequestAction();
return fetch(`${store.baseURL}/resource`)
.then(response => {
if (response.ok) {
return response.json()
.catch(error => {
throw new Error(`JSON parse error: ${error.message}`);
});
} else {
throw new Error(`${response.status} ${response.statusText}`);
}
}, error => {
throw new Error(`Network error: ${error.message}`);
})
.then(dispatchSuccessAction, dispatchFailureAction);
We're having a hard time figuring out how context (or specifically { commit } is handled in chained promises with transpiled ES6 code. Below is one example of a Login action that authenticates and then subscribes using RxJS to the user as a stream. We need to commit several mutations throughout the process, but keep getting commit is not a function errors.
Does anyone know of or have an example of something like this or can anyone provide any basic guidelines on where and how context/commit are handled in this scenario - e.g. when can ES6 be used vs not, and/or where is context hoisted or not (if at all), and or is there a simpler approach to all this like maybe wrapping things all in a master promise? Since we need to potentially commit at each step in the promise chain, we cannot see how some of this could work:
const actions = {
login ({commit}, creds) { // need to commit here
commit('toggleLoading')
api.authenticate({
strategy: 'local',
...creds
})
.then(function (result) {
return api.passport.verifyJWT(result.accessToken)
})
.then(function ({commit}, payload) { //need to commit here
console.log(commit)
return api.service('users').get(payload.userId)
.subscribe(commit('setUser', user)) // need to commit here - but commit is not a function error
})
.catch(function ({commit}, error) {
commit('setErr', `ERROR AUTHENTICATING: {$err.message}`) // need to commit here but commit is not a function error
commit('toggleLoading')
})
}
All of the examples we find are way simplistic and only show one commit per action (or maybe 2 wrapped in an if). Any help or feedback is appreciated!
Firstly, the callback functions in .then and .catch take a single argument, you've coded two ... however, commit from the login arguments is still in scope, so it's quite simple to fix
Your code can be simplified as follows
const actions = {
login ({commit}, creds) {
commit('toggleLoading');
api.authenticate({strategy: 'local', ...creds})
.then(result => api.passport.verifyJWT(result.accessToken))
.then(payload => api.service('users').get(payload.userId).subscribe(commit('setUser', user)))
.catch(function (error) {
commit('setErr', `ERROR AUTHENTICATING: ${error.message}`);
commit('toggleLoading');
});
}
Note: you have {$err.message} in the .catch, whereas I beleive that should be ${error.message}
I have a popular scenario where I need to create one promise that returns data which is fed to a second promise.
If the first promise fails, I need to cancel the second promise.
In 'Promise' land it would look something like this:
Fn1.doPromise( initialData )
.then(info => {
Fn2.doPromise( info )
.then(result => {
//success - return result
})
.catch(error => {
//error
});
})
.catch(error => {
//cancel 2nd promise and show error
});
Now I am trying to learn the best way to do this using Observables with something like RxJS. Can anyone give me a good solution ?
Thank in advance !
The general issue of error handling with RxJS is dealt with here. Main points are :
Catching Errors (with catch operator, either at instance level or at class level)
Ignoring Errors with onErrorResumeNext
Retrying Sequences (with retry)
Ensuring Cleanup (with finally)
Ensuring Resource Disposal (with finally or using)
Delaying Errors (with mergeDelayError)
About your specific question you can use Rx.Observable.fromPromise to convert a promise into an observable; Rx.Observable.prototype.catch to catch errors as they occur.
Rx.Observable.fromPromise(Fn1.doPromise( initialData ))
.flatMap(info => {
return Rx.Observable.fromPromise(Fn2.doPromise( info ))
.flatMap(result => {
//success - return result
// !! You must return an observable or a promise here !!
})
.catch(error => {
//error
// !! You must return an observable here !!
});
})
.catch(error => {
//cancel 2nd promise and show error
// !! You must return an observable here !!
});
Examples :
first error handler activated
no error
inner error handler activated
I was also able to find a nice generic solution for my promise 'chaining' after doing some more research. With this I can use an many promises as I need.
const flatMapAll = (...fns) =>
fns.reduce((acc, fn) =>
acc.flatMap(fn), Rx.Observable.just())
flatMapAll( p1 ,p2 ,p3).subscribe();