multiple functions inside of angular then() - javascript

Sometimes I see more than two functions separated by comma, inside of promise then() in AngularJs. Could anyone here help to explain what the structure mean?
e.g.
then(function(response){..}, function(response){..}, function(response){..}, function(response){..});
I understand that, if there are two functions inside of then(). The first function will run if it fulfill the promise, otherwise the second will run if there is any error occurs. This structure doesn't look like chained promise either...
Thank you very much for any help here :-)

Well:
The first function is the fulfillment handler, it will execute when the promise resolves to a value (normally).
The second function is the rejection handler, it will execute when the promise resolves with an error by rejecting (or throwing an exception in a handler).
The third function is for progress, this is a nonstandard and deprecated feature that will never be a part of ECMAScript promises - it is best to avoid it altogether since it does not compose well. It is also not supported in Angular's new $q API.
Anything past the third function passed in is ignored by the handler and will have no effect.
Here is an example for all three being called:
var good = $q.when(3);
good.then(x => console.log("Successful"));
var bad = $q.reject(Error("Bad")); // always reject with errors
bad.then(null, x => console.log("Failed"));
var d = $q.defer(); // don't do this like... ever
d.promise.then(null, null, x => console.log("Progressed"));
d.notify("event notification"); // never use this in real code ;)

Related

How does this promise without an argument work in this mutation observer?

I was looking at this mutation obersver in some typescript code and I can’t figure how the promise works in it, I’ve not see a promise without an argument in this style before:
const observer = new MutationObserver((mutations: MutationRecord[]) => {
Promise.resolve().then(someNextMethod)
this.somethingThatTakesAWhile()
})
observer.observe(HTMLtarget)
When the observation is triggered the someNextMethod runs after this.somethingThatTakesAWhile() has ran. How is this possible in this instance? I don't understand how the Promise get passed any arguments and knows how to resolve in this case. Could someone explain the internal mechanics of this code please? I'm at a bit of a loss as to how it runs in that order. Thanks!
The main point of something like this:
Promise.resolve().then(someNextMethod)
is just to call someNextMethod() after the current chain of execution finishes. In a browser, it is similar to this:
setTimeout(someNextMethod, 0);
though the Promise.resolve() method will prioritize it sooner than setTimeout() if other things are waiting in the event queue.
So, in your particular example, the point of these two statements:
Promise.resolve().then(someNextMethod)
this.somethingThatTakesAWhile()
is to call someNextMethod() after this.somethingThatTakesAWhile() returns and after the MutationObserver callback has returned, allowing any other observers to also be notified before someNextMethod() is called.
As to why this calls someNextMethod() later, that's because all .then() handlers run no sooner than when the current thread of execution completes (and returns control back to the event loop), even if the promise they are attached to is already resolved. That's how .then() works, per the Promise specification.
Why exactly someone would do that is context dependent and since this is all just pseudo-code, you don't offer any clues as to the real motivation here.
This:
Promise.resolve().then(someNextMethod)
Is equivalent to this:
Promise.resolve().then(() => someNextMethod())
Working backward is equivalent to:
const myNewMethod = () => someNextMethod()
Promise.resolve().then(myNewMethod)
Defining a function inline or pointing to a function is just a syntactical difference. All of the arguments passed through then will be passed to the referenced function. But in this case, there isn't any as it's a promise with an empty return value.
In other words, the method doesn't need any parameters. In this instance it's actually just an old JS hack/trick to get the code to run at the end of the call stack.

Javascript Promise Single Function Callback

I have two ways to run a series of initialisations (that need to happen in a particular order).
Method 1:
dispatch('initialize1')
.then(dispatch('initialize2'))
.then(dispatch('initialize3'))
.then(dispatch('initialize4'))
.catch((error) => Log(error.message))
Method 2:
dispatch('initialize1')
.then(() => dispatch('initialize2'))
.then(() => dispatch('initialize3'))
.then(() => dispatch('initialize4'))
.catch((error) => Log(error.message))
Method 2 works perfectly, but Method 1 seems to not wait for each to finish before it moves onto the next one.
But this really confuses me because I thought that if I chained promises with thens (no callback function), it would wait for each to complete (synchronously); but if I put each promise in a callback then as soon as it received the promise it'd move onto the next - but it's the opposite??
Can anyone explain this to me?
I don't think it's relevant, but the dispatch comes from Vue's Vuex Store.
In method 1, you passed the result of calling the function dispatch instead of passing a function to the Promise chain, this will cause the dispatch functions be called first before the Promise chain actually starts executing, i.e. the dispatch functions has already been called when you initialize the chain.
You can check it out directly by running the following code right at your browser's console:
const dispatch = something => something
typeof dispatch('apple') === 'string' // true
typeof (() => { dispatch('apple') }) === 'function' // true
In method 2, you are passing functions this time, so the functions will be called at the right time by Promise, instead of being run at start.
Because you need a wrapper function in the first case:
.then(function() {
dispatch('initialize2')
})
Here you do the same thing:
.then(() => dispatch('initialize2'))
() => ... is a wrapper function similat to function() {...}.
You should take a look at how promises are supposed to work. In short they are made of two pieces, a resolvealgorithm and a then method available on promise instances. Your first example cannot work because it does not follow the semantics ( signature ) of the then method.
They are as follow : let p a promise, f a JS value. Calling p.then(f) we have the following case :
if f is not a function it is ignored, and p.then(f) returns a new promise q eventually settled with the same state as p.
if f is a function then when p is settled with a value, calling p.then(f) will return a new promise q which will be settled with the value / error produced by f. This is the critical part and what makes promises interesting : the procedure you pass in to the then attr will only be called after a value / error has first been produced by the original promise, hence your issue with example 1.
There is ofc a little bit more than that to promises and their semantics : thentakes two arguments, one for each path : value / error. The namings may differ but usually you see code along the lines :
p.then(proceed, handle)
with
function proceed ( successfulValueFromSomewhere ) { // return new value or promise }
function handle ( anErrorFromSomewhere ) { // handle it by returning a value or a promise ( for retry cases ) }
I mentioned earlier a resolve algorithm, this part is critical to understand how values returned from such handlers are used from the point of view of promises to create new promise.
This procedure ensures that your second example work, it works more or less like that ( please take a look at the specs or the docs at MDN for an in depth review ). Its purpose is to transition a promise to one of two states : fulfilled with a value or rejected with an error.
Let v be a value, p an unsettled promise to be resolved with v.
if v has a then method then call it with the function function ( v2 ) { resolve(v2); } : which means that if the callback is called, rerun the procedure with the value provided (v2).
if v does not have a then method then fulfill with v
if at any point an error is thrown during the resolution then rejectwith the error.
This procedure is not really difficult and explains why promises compose nicely together : they will call each other's thenmethod upon resolution, which means that they will execute sequentially if each callback returns a promise.
There is a bit more than that to the specs of promises, I strongly advise anyone to take a look at the articles on MDN and this article about the motivations behind this new primitive added to the language and how it solves (some) problems.
If this answer is obscure please comment I'll try to be clearer :)

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

What does "Promise fires on the same turn of the event loop" mean?

New to NodeJS. Going through the promise tutorial ('promise-it-wont-hurt') I have the following script:
var Q = require('q');
var deferred = Q.defer();
deffered.resolve('SECOND');
deffered.promise.then(console.log);
console.log('FIRST');
The output:
FIRST
SECOND
I don't get it, I would have thought that since resolved is fired first I should see second first.
They explain that this happens because of 'Promise fires on the same turn of the event loop'. I don't understand what that means...
Basically, the point is that the promise's then handler will not run before the current flow of code has finished executing and control is returned to the execution environment (in this case Node).
This is an important characteristic of Promises/A+ compliant promises because it ensures predictability. Regardless of whether the promise resolves immediately:
function getAPromise() {
var Q = require('q');
var deferred = Q.defer();
deferred.resolve('SECOND');
return deferred.promise;
}
getAPromise().then(console.log);
console.log('FIRST');
or whether it resolves after 10 seconds:
function getAPromise() {
var Q = require('q');
var deferred = Q.defer();
setTimeout(function () {
deferred.resolve('SECOND');
}, 10000);
return deferred.promise;
}
getAPromise().then(console.log);
console.log('FIRST');
you can be assured that FIRST will always be logged first.
This is discussed at length in chapters 2 and 3 of You don't know JS - async & performance. Asynchronous operations that sometimes run asynchronously and sometimes run synchronously are called Zalgos, and they are not considered to be a good thing.
It's important to note that the widely used promises in jQuery do not obey this behavior and have a number of other problems as well. If you find yourself with a jQuery promise, wrap it in a proper promise and proceed:
Q($.ajax(...)).then(breatheWithEase);
They explain that this happens because of 'Promise fires on the same turn of the event loop'. I don't understand what that means...
Me neither, imho this part doesn't make much sense. It probably should mean that when you call resolve or reject, the promise is settled immediately, and from then on will not change its state. This has nothing to do with the callbacks yet.
What is more important to understand is the next sentence in that paragraph:
You can expect that the functions passed to the "then" method of a promise will be called on the NEXT turn of the event loop.
It's like a simple rule of thumb: then callbacks are always called asynchronously. Always, in every proper promise implementation; this is mandated by the Promises/A+ specification.
Why is this? For consistency. Unlike in your example snippet, you don't know how or when a promise is resolved - you just get handed it back from some method you called. And it might have already been resolved, or it might be still pending. Now you call the promise's then method, and you can know: it will be asynchronous. You don't need to deal with cases that might be synchronous or not and change the meaning of your code, it simply is always asynchronous.

What is the q.catch() equivalent for parse promises?

In the Q-promise library, if there is a random problem like TypeError: Cannot read property 'blah' of undefined then it can be handled via the Q.catch() block.
But in Parse-promise library, if there is such a problem inside a then() block, I currently see no way of handling it other than putting a try/catch inside every single then() block!
Am I missing something? What is the q.catch() equivalent for parse promises?
Or are such errors simply impossible to capture without a try/catch block in every then() block?
.then(function(data)){
try{
// do something with data that might throw an exception/error
}
catch(exception){
return Parse.Promose.error(exception);
}
})
As per spec, the .then() function in all Promises/A+ compatible libraries (including the Parse-promise library) takes two callbacks - onFulfilled and a onRejected. If the first argument ie. onFulfilled throws an exception, the promise is rejected and the second argument will be called.
In other words, your example can be rewritten:
.then(function (data) {
// do something with data that might throw an exception/error
}, function (exception) {
// handle the exception
})
In addition, Parse-promises (like many promise libraries) provides additional APIs to make this neater. Specifically, you can use .fail() to wire up callbacks to get called if the promise is rejected.

Categories

Resources