How to break sequence handlers of Promises/A? - javascript

How to break sequence of handlers of Promises/A?
For example
if we have sequence:
method1().then(method2())
.then(method3(), errorHandler3());
and in method2() we decided to break sequence and don't go farther nor to method3() or errorHandler3(). What we should do?

You can return a promise that never is resolved from the function that method2() yields.
However, that doesn't make much sense, as "breaking the sequence" means going to error state actually, and should be possible to handle.
Maybe you rather want
method1().then(function method2(res) {
// do something
if (/* you want to break*/)
throw new Error("reason for breaking");
else
return when(/* what is done */).then(method3(), errorHandler3());
});

In that case you should nest your logic in a callback passed to then, e.g.
method1().then(function (value) {
if (method2(value)) return method3();
}).done();
I simplified my example, so it doesn't take callbacks from other function calls (as it is in your code). It looks a bit weird, and definitely is not common in promises world, what is your reasoning behind it?
Commenting on other solution, you definitely should not use promise that never resolves. In well written logic all promises resolve, and if there are ones that doesn't it means you have a bug in your logic (it's like creating async function that is never meant to call a callback, doesn't make sense).

Related

Reusing an existing Promise object if exists

I have a Dialog object that will show, well, dialogs. There are many entry points to show dialogs, e.g. yesNo(), message(), confirm(), etc. However, all these methods basically call the same other method, called showSimpleDialog(title, message, buttons).
I'd like all these methods (showSimpleDialog too) to return a promise, but there's a snag:
yesNo() {
return new Promise((resolve, reject) => {
axios
.get(......)
.then(this.showSimpleDialog(...));
}
}
As you can see, I am prevented in the above example from either returning the promise that showSimpleDialog would make or by passing the instanced Promise to showSimpleDialog.
The former is impossible because we're already in a different Promise by the time we have access to it. The latter because the Promise object itself is not yet available within the constructor. Well, technically, in this particular case it is (exactly because we're already in a different Promise), but some of my entry functions are synchronous, some asynchronous and I simply can't use the same code pattern to achieve the same effect in both cases.
I investigated the thing and I found this, but the author suggests the approach is flawed and archaic to begin with.
So, what would be the correct approach to return a functioning Promise from ALL entry points while the entry points would still be free to reusing each other's Promises?
If I understand correctly, this.showSimpleDialog(...) also returns a Promise, right?
If you want yesNo() to return the Promise retunred by this.showSimpleDialog(...)
yesNo() {
return axios
.get(......)
.then(()=>{
return this.showSimpleDialog(...);
});
}
That being said, consider using async/await, especially when dealing with multiple sequential promises, if possible.
Your code is calling this.showSimpleDialog immediately (synchronously) without waiting for any promise to resolve (the axios one). This is because the code doesn't pass a function to the then method, but instead executes this.showSimpleDialog. This execution returns a promise (presumably), but then expects a function as argument, not a promise.
So you need to make sure to pass a callback to then, and let that callback return a promise. This way promises will be chained:
.then(() => this.showSimpleDialog(...));
It is also important to make that callback an arrow function, since you'll be referencing this, which is intended to be the this on which yesNo is called.

Why using Promise()?

No matter how many tutorials I read, I still don't understand why I should use Promise()?!
Ok, let's make an example:
let cleanedUpMyRoom = new Promise(function(resolve, reject) {
if (true === true) {
resolve(true);
}
else {
reject(false);
}
});
cleanedUpMyRoom.then(function(result) {
console.log(result);
});
This code returns either true or false.
function cleanedUpMyRoom() {
if (true === true) {
return true;
}
else {
return false;
}
}
console.log(cleanedUpMyRoom());
This code also returns either true or false.
Why would I use the first code, if the second code is shorter and easier to read?
As several people have pointed out, promises are typically used to serialize asynchronous operations. The idea was developed as an alternative to nested callbacks, and what people have often referred to as "callback hell". E.g. something with callbacks like:
asyncFn1(
function(result1){
asyncFn2(result1,
function(reult2){
asyncFn3(result2)}
)}
)
can be rewritten using promises like:
asyncFn1()
.then(function(result1){asyncFn2(result1)})
.then(function(result2){asyncFn3(result2))
For complex cases where there are both success and failure handlers and functions depend on the results of other asynchronous operations, this can simplify the logic and greatly improve readability.
To look at your cleanedUpMyRoom example, a more common implementation would be to write:
cleanUpMyRoom = function(){
cleanPromise = new Promise();
startCleaning(/*on success*/ function(){console.log('Room cleaned!');
cleanPromise.resolve()},
/*on failure*/ function(){console.log('Room cleaned!');
cleanPromise.resolve(result)})
// or *alternatively* if it's just plain synchronous,
// var result = cleanIt()
// if (result = "success")
// cleanPromise.resolve()
// else
// cleanPromise.reject(result)
return cleanPromise
});
then
cleanUpMyRoom.then(goGetIceCream(),contemplateFailure(result))
cleanUpMyRoom() always returns a promise that has a then function. The important piece is that the function passed to then isn't called until the promise is resolved or rejected, and the result of the promise generating function is ready (whether synchronously or asynchronously).
Ultimately, a promise lets you chain together operations whose results may not be available in the synchronous procedural code so that nothing is called until the available, possibly asynchronous (like network requests), preconditions are met, and you code is able to manage on to other events in the meantime.
Take a look at this:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
You also might be interested in the upcoming (ES2017) async/await syntax which is becoming popular and handles many asynchronous situations without explicitly using promises at all:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function
Javascript is an event driven language. In your short example, you are correct that using a promise would be pointless. In a more complex situation, say an AJAX request to the server, the code won't execute immediately.
Javascript will not work by simply returned the value as other imperative languages like python or java. The promise is advantageous by not blocking the main thread, and the code will begin running once the promise has been fullfilled. It makes javascript a great language for managing short spurts of activity through the event abstraction.

Can a function either return a promise, or not?

So that the caller of the function (the user of the service) can use .then if he wants to do something with the information the function generates. If he doesn't care when it gets done, as long as it gets done sometime, he can just call the function without any .then infrastructure.
Will this work? I don't want to get into a situation where it will work in my tests, but in some obscure situation that doesn't happen very often, it will fail.
Hmm. I guess what I mean is this. If I am writing the routine that returns the promise, I have to say:
return new Promise(function (resolve, reject) { ... });
If my caller doesn't say:
.then(function () { ... }, function () { ... });
what will happen? I will at some point call resolve() or reject(), and resolve and reject won't be defined. Does the Promise constructor supply some default (do nothing) definition?
I suppose if I am a crazy person, I can say in my callee function:
(resolve || function () {})();
A function that returns a promise will do what you'd like it to do.
Given a function B():
If the user does not chain B().then(), they will get the answer eventually whenever it is done. It is up to them to handle the fact that they don't know when the value is populated. That is to be expected.
If the user does chain B().then(), they will have a nice and easy way to control what happens once the value is returned.
You do not need to worry about weird edge cases. A function that returns a promise is a clear and straightforward contract.
As with all functions in Javascript, the caller is free to ignore a return value. The Javascript garbage collector will take care of objects or values that are no longer in use.
So, if the caller of some async operation that returns a promise really doesn't care when it's done OR if there are errors, then the caller is free to just ignore the returned promise. Nothing bad happens (other than the fact that you may never know there are errors).
The part of your question that does not seem to be cool with this is where you say: "If he doesn't care when it gets done, as long as it gets done sometime". If you are ignoring async errors, then this may not actually get done sometime and you may never know that. In this case, it might be more appropriate to do:
someAsyncFunc(...).catch(function(err) {
console.err(err);
// so something meaningful with the error here
});
Unless you specifically need to wrap a legacy API, using the Promise constructor is an antipattern. Use the Promise factories instead, or if using bluebird, see if you can use bluebird's promisify on the legacy function.
You also seem to be misunderstanding what the parameters to the Promise constructor function argument are. They are not the callbacks, they are the functions that settle the Promise. The Promise itself will worry about notifying any callbacks, if they exist.
Also, if your function sometimes returns a Promise, and sometimes does not, you might crash any code that assumes it can call .then on your function's return value. Don't do that.
If your computation may be async, always return a Promise. If you want to return a value that is already settled, then return Promise.resolve(theValue).

Return non-returning function from Promise results in Warning

I have a nodejs express app and I use a library which has a typical callback interface for executing functions. My persistence layer uses a promise based approach. I have the following code which bothers me
getUserByName('dave')
.then(function (user) {
// check stuff and call the callback with success
return cb(null, true);
})
.catch((err) => cb(err, false));
Problem: the cb(null, true) functions returns undefined and the promise ends with this warning a promise was created in a handler but was not returned from it.
I can fix this by running the callback and then do return null like this:
// check stuff and call the callback with success
cb(null, true);
return null;
But now I'm asking myself is it really waiting for the callback to finish? Is this the correct way to handle this kind of warning? I have the feeling I'm doing it wrong.
I remember having the same problem when writing an express middleware and then inside a promise calling the next() function to jump to the next middleware. It also returns undefined. Any suggestions to handle this?
Well, the proper solution would of course be to switch to a framework that doesn't use node-style callbacks and leverages promises, so that you could simply return your promise and wouldn't need to call any callbacks passed to you.
If that is not possible, you still should not call such callbacks from your normal code. The warning is correct, you are calling something (the callback) that does more asynchronous work (creates other promises) but are not returning that into your chain ("forgetting" to wait for it), a common mistake. Your explicit return null suppresses this warning correctly, but there's actually a much better way:
Write your code as if you already were returning promises, and then invoke .asCallback which is dedicated for this very purpose (including not issuing warnings):
getUserByName('dave')
.then(function (user) {
// check stuff and call the callback with success
return true;
})
.asCallback(cb)
But now I'm asking myself is it really waiting for the callback to
finish? Is this the correct way to handle this kind of warning? I have
the feeling I'm doing it wrong.
The Javascript execution in node.js is single threaded so the code is waiting for any synchronous code in cb() to finish. If cb() does async operations (which the warning you are getting makes me think it is), then your code is NOT waiting for those asynchronous operations to finish.
Whether or not your work-around is the correct way to handle that warning depends upon what is happening in the callback and whether your code needs to wait for any async operations in that callback to actually complete. If your code does not need to wait for them, then adding the empty return is perfectly fine and just tells the promise library that you are purposely not returning a promise that was created inside the .then() handler which is an OK thing to do in some circumstances.
If, on the other hand, you do need to wait for the asynchronous operations inside of the callback to complete, then you need the callback's help in order to be able to do that by making it either return a promise or for it to have a completion callback itself (though the promise would be a lot easier in this case).

Readable promise logic flow

I am trying to figure out what the best practice is for structuring Promise logic with both modals and http requests. Say I have a situation like this:
// normal logic flowing to here
// ...
// encounter special case
if (needToDoSomeGuidedPreprocessing) {
doSomeAsyncHttpCall
.then(doSomeStuff);
.then(sendUpSomeDialogThatNeedsToConfirmToProceed)
}
// ...
// if dont need guided preprocessing, continue to normal operations
// (includes more dialogs). Also, if guided preprocessing worked, make sure
// code down here doesn't fire until pre-processing is done (i.e. all these
// operations need to be done sequentially, so .all( ) wont work
How can I accomodate my code to be readable here?
I thought of this but thought maybe there is some better way? The problem is that I have yet more async methods/dialogs after this, and would prefer to keep in a singular method rather than jumping out to an entirely new method.:
// ...
// encounter special case
if (needToDoSomeGuidedPreprocessing) {
doSomeAsyncHttpCall
.then(doSomeStuff);
.then(sendUpSomeDialogThatNeedsToConfirmToProceed)
.then(callSomeCommonMethod)
}
else{
callSomeCommonMethod()
}
// ...
Is this just the nature of dialogs/async operations or am I doing something wrong?
If your operation could be async, it should always be treated as if it's async to the outside world, even if under certain (or even most) conditions it is sync.
So, to accomplish that, the function should return a promise.
Other than that, .then chaining provides the sequential processing you need. Otherwise, your code is pretty readable.
function doSomething(){
var promise = $q.resolve();
if (needToDoSomeGuidedPreprocessing){
promise = promise.then(doSomeAsyncHttpCall)
.then(doSomeStuff)
.then(sendUpSomeDialogThatNeedsToConfirmToProceed)
}
promise = promise.then(callSomeCommonMethod);
// etc...
return promise;
}

Categories

Resources