Difference between chaining promises vs values in .then methods? - javascript

for a while, I thought the only way to chain .then() statements was to return a promise from the .then method. e. g.:
asyncFunc()
.then(res => asyncFunc2()) // returns a promise
.then(res => doSmth())
But now I figured out that you can actually also return a plain old value from the .then function and it also works:
const build = () => new Promise((resolve, reject) => {
setTimeout(() => {
resolve("Hallo")
}, 100)
})
build()
.then(res => {
console.log(res);
return res + " I'm";
})
.then(res => {
console.log(res + " Peter");
})
Is there a difference between the two in terms of how and when they are executed?

Each .then() method call returns a promise, if the return value of the callback function is also a promise, then the promise returned by the .then() method call gets resolved to that promise, meaning its fate will now depend on what happens to the promise returned by the callback function. It will settle when the promise returned by the callback function settles.
On the other hand, if you return a non-promise value, then that value is implicitly wrapped in a promise and passed to the next .then() method call, if there's any. If you don't return anything from the callback function, the promise returned by the .then() method will resolve with the value of undefined.
In first code example, as you are returning asyncFunc2() from the callback function of first .then() method, the promise returned by it will get resolved to the promise returned by asyncFunc2().
In the second code example, res + " I'm" will be implicitly wrapped in a promise and then passed to second then() method.

Related

How to access value from a promise in typescript? [duplicate]

I am trying to wrap my head around promise object in JavaScript. So here I have this little piece of code. I have a promise object and two console.log() on either side of the promise object. I thought it would print
hi
There!
zami
but it printed
hi
zami
There!
Why it is like that? I have zero understanding on how promise works, but I understand how asynchronous callback works in JavaScript. Can any one shed some light on this topic?
console.log('hi');
var myPromise = new Promise(function (resolve, reject) {
if (true) {
resolve('There!');
} else {
reject('Aww, didn\'t work.');
}
});
myPromise.then(function (result) {
// Resolve callback.
console.log(result);
}, function (result) {
// Reject callback.
console.error(result);
});
console.log('zami');
Summary:
A promise in Javascript is an object which represent the eventual completion or failure of an asynchronous operation. Promises represent a proxy for a value which are getting in some point in the future.
A promise can have 3 states which are the following:
Pending: This is the initial state of the promise, the promise is now waiting for either to be resolved or rejected. For example, when are reaching out to the web with an AJAX request and wrapping the request in a promise. Then the promise will be pending in the time window in which the request is not returned.
Fulfilled: When the operation is completed succesfully, the promise is fulfilled. For example, when we are reaching out to be web using AJAX for some JSON data and wrapping it in a promise. When we are succesfully getting data back the promise is said to be fulfilled.
Rejected: When the operation has failed, the promise is rejected. For example, when we are reaching out to be web using AJAX for some JSON data and wrapping it in a promise. When we are getting a 404 error the promise has been rejected.
Promise Constructor:
We can create a promise in the following manner:
let prom = new Promise((res, rej) => {
console.log('synchronously executed');
if (Math.random() > 0.5) {
res('Success');
} else {
rej('Error');
}
})
prom.then((val) => {
console.log('asynchronously executed: ' + val);
}).catch((err) => {
console.log('asynchronously executed: ' + err);
}).finally(() => {
console.log('promise done executing');
});
console.log('last log');
Points of interest:
The code inside the promise constructor is synchronously executed.
then method takes as a first argument a callback which is asynchronously executed on promise fulfillment.
then method takes as a second argument a callback which is asynchronously executed on promise rejection. However we are usually using the catch method for this (because this is more verbose), which also takes a callback which is asynchronously executed on promise rejection. catch is essentially the same as then(null, failCallback).
The then callback receives as a first argument the resolved value (the string 'success' in this case).
The catch callback receives as a first argument the rejected value (the string 'Error' in this case).
The finally method receives a callback which is executed on both promise fulfillment and rejection. Here we can write 'cleanup' code which need to be executed always regardless of promise outcome.
Your example:
In your code 'Zami' was printed before 'there' because the log which logged 'there' was in a then callback function. We earlier pointed out that these callbacks are executed asynchronously and thus will be executed last.
Promise execution is asynchronous, which means that it's executed, but the program won't wait until it's finished to continue with the rest of the code.
Basically, your code is doing the following:
Log 'Hi'
Create a promise
Execute the promise
Log 'zami'
Promise is resolved and logs 'There'.
If you want it to print 'Hi there, zami', you will have to
myPromise.then(function (result) {
// Resolve callback.
console.log(result);
console.log('zami');
}, function (result) {
// Reject callback.
console.error(result);
});
Even though you resolved the promised synchronously, the handlers you pass into then get called asynchronously. This is according to the defined specification:
onFulfilled and onRejected execute asynchronously, after the event loop turn in which then is called, and with a fresh stack
I would recommend you to understand how event loop works in JavaScript.
take time and watch this Video.
It will clear your doubts.
A Promise is an object representing the eventual completion or failure of an asynchronous operation.
Below is the example of promise:
const post = new Promise((resolve, reject) => {
resolve("Appended from getPostWithPromise()");
});
const getPostWithPromise = function () {
post
.then(function (fulfilled) {
$("body").append("<div>" + fulfilled + "</div>");
})
.catch(function (error) {
console.log(error);
});
}
function getPostWithoutPromise() {
$("body").append("<div>Appended from getPostWithoutPromise()</div>");
}
$(function () {
getPostWithPromise(); // this will print last
getPostWithoutPromise(); // this will print first
$("body").append("<div>Appended directly</div>"); // second
});
you can test it => JavaScript Promises example
for detail understanding you can read this post => https://scotch.io/tutorials/javascript-promises-for-dummies
Promise:
new Promise((resolve, reject) => {
resolve(whateverObject)
reject(whateverErrorObject)
})
It is just object that can be chained with then()
You also can make promise! you can return whatever object in that success parameter (resolve) and error parameter (reject)
so very simple concept bro!
Promises are objects.
Each promise object has a then method.
The then method of the promise object accepts a function as a first parameter.
If we call the then method of a promise, the callback function will be executed once the promise gets resolved.
Flow of execution
const promiseObj = new Promise((res, rej) => {
console.log("Promise constructor are synchronously executed");
res("Hii Developer");
})
const callbackFunction = (resolvedValue) => console.log("Resolved Value ", resolvedValue);
promiseObj.then(callbackFunction);
console.log("I am the executed after the constructor");
In the above example, we have created a promise object using the Promise constructor.
The constructor function is synchronously executed.
After creating the promise object, we are calling the then method of the promise object. We have passed a callback function in the first argument of the then method. This callback function will be executed once the promise gets resolved and the stack of the js engine gets empty.
Promise is a object that represents the completion or failure of a event . Promise is a asynchronous thing in JS which means that it's executed, but the program won't wait until it's finished to continue with the rest of the code. So it wont be executed simultaneously. It would take time to either complete or fail for a given task and then execution.
In your Case
log'Hi'.
First your mypromise variable will store a promise object i.e either rejected or resolved(for this, it would take time)
But JS engine will execute further code first then the asynchronous task. SO u will get 'zami'.
once the promise resolved or rejected. It will be called or used wherever it is used in the code. In this case ,it is resolved and log 'there!' in console.
let prom = new Promise((res, rej) => {
console.log('synchronously executed');
if (Math.random() > 0.5) {
res('Success');
} else {
rej('Error');
}
})
prom.then((val) => {
console.log('asynchronously executed: ' + val);
}).catch((err) => {
console.log('asynchronously executed: ' + err);
}).finally(() => {
console.log('promise done executing');
});
console.log('last log');

JS Promise class confusing return values in chained behavior

Please help me to understand the following behavior of the Promise class. I have spend a lot of time reading instructions and documentation but can't figure this out by myself.
const promise = new Promise(resolver=>
setTimeout(resolver("i am resolver"), 1000)
)
.then(resolvedParameter => el => {console.log(el); console.log(resolvedParameter)})
.then(upperFunc => upperFunc("log me this"))
.then(() => console.log("do not care about the others"))
.catch(e => (error = e));
promise.then(()=>console.log("test"));
This is the console output:
log me this
i am resolver
do not care about the others
test
In the Promise where setTimeout is used no return value was specified, jet the string "i am resolver" was returned and used in the first then(). I presume that when you call resolver (as a promise resolver function) it returns the passed parameter for the next then()
In the first then() the resolvedParameter is passed in function that returns a function that will be returnd and then used in the second then() which is logical, and the string from the first promise is remembered ("i am resolver") and used correctly.
Can you make a then() function with resolver and rejection function ? Please help me understand what ways do we have available to pass data from first promise to the next function then() and what is expected to be returned from the then() function. (I read and understood that they are new Promises but still the behavior is a bit hard to understand)
Thank you for reading this question and any insight is welcome.
For background information, here are different ways to make a resolved promise:
promise = new Promise(resolver => resolver('any value'));
promise = Promise.resolve('any value');
promise = Promise.resolve().then(() => 'any value');
promise = (async () => 'any value')()
They are functionally equivalent. They all return a promise that is resolved with the value 'any value'.
.then() function gets, as the first argument, whatever is resolved previously up the chain and can return three different ways:
If it returns a normal value, that is passed down the chain as the resolved value.
If it throws a value, that value is passed down the chain as rejection.
If it returns a promise[1], then what ever that promise resolves or rejects as is passed down the chain as resolved value or rejection.
All your examples fall into the first category. Here is a list of values passed down in the resolved promises:
"i am resolver"
el => {console.log(el); console.log(resolvedParameter)}
undefined // because that is what the above function returns when called
undefined // because that is what the console.log returns
undefined // again console.log return value
Here is an example where I have wrapped all your returns values inside promises:
const promise = new Promise(resolver=>
resolver(Promise.resolve("i am resolver"));
)
.then(resolvedParameter => Promise.resolve(el => {console.log(el); console.log(resolvedParameter)}))
.then(upperFunc => Promise.resolve(upperFunc("log me this")))
.then(() => Promise.resolve(console.log("do not care about the others")))
.catch(e => Promise.resolve(error = e));
promise.then(()=>Promise.resolve(console.log("test")));
This functions identically to your example, but hopefully it is clear now what is passed down the chain.
As others have mentioned, the second argument of .then() is called when rejection is passed from the chain. It works the same as the .catch() method. .then(undefined, someFunc) is same as .catch(someFunc).
[1] Strictly, it can also be a "thenable", something that has a then method, but that is a special case.

Promises chaining, wrong order

I'd like to understand the promises chaining in Javascript. So I wrote this little fiddle:
https://jsfiddle.net/GarfieldKlon/89syq4fh/
It works like intended. c waits for b, and b waits for a.
But when I change these lines to:
a().then( result => console.log(result))
.then( () => {b().then( result => console.log(result))})
.then( () => {c().then( result => console.log(result))});
So I added the curly braces around b and c and then the output is 1, 3, 2. And I don't understand why.
When I add a return then it works again:
a().then( result => console.log(result))
.then( () => {return b().then( result => console.log(result))})
.then( () => {return c().then( result => console.log(result))});
But why? When there are no curly braces you're only allowed to write one statement, correct? And this statement is implicitly returned?
And when you use curly braces you have to explicitly return something?
But why does it mess up the order when using curly braces without return? And why does it still log something when the return is missing?
When there are no curly braces you're only allowed to write one expression which is implicitly returned?
And when you use curly braces you have to explicitly return something?
Yes.
But why does it mess up the order when using curly braces without return? And why does it still log something when the return is missing?
Because the promise then function relies on return values for chaining.
Remember that then returns a new promise for the result of the callback. When that result is another promise, it waits for the result of that inner promise before fulfilling the returned promise - the one on which you are chaining the second then() call.
If your callback starts b().then(…) but returns undefined, the next step in the chain (the c() call) doesn't wait for b to finish.
When using the arrow syntax, you can interpret it in many things:
() => 'hello'
is equivalent to
() => { return 'hello'; }
However, when doing
() => {'hello'}
as similar to what you wrote:
.then( () => {b().then( result => console.log(result))})
then you can interpret that as
() => {'hello'; return;}
So, in the code, yours promise handling b().then( result => console.log(result)) is called before a void return; is done. You are not returning the resulting promise object at all. It gets called when b is finished, no matter of what you were doing.
This has to do with arrow functions. When you omit the curly braces, the return is implicit. So
const f = () => 42;
is equivalent to
const f = () => { return 42; };
Also, b().then(something).then(somenthingElse) is still only one expression, so it can be implicitly returned.
A Promise is an object that represents the result of an asynchronous operation.
It is important to remember that Promises are not just abstract ways registering callbacks to run when some async code finishes — they represent the results of that async code.
When we write a chain of .then() invocations, we are not registering multiple callbacks on a single Promise object. Instead, each invocation of the then() method returns a new Promise object.
That new Promise object is not fulfilled until the function passed to then() is complete. The value that fulfills promise 1 becomes the input to the callback2() function. The callback performs some computation and returns a value v. When the callback returns the value, the promise is resolved with the value v.
When a Promise is resolved with a value that is not itself a Promise, it is immediately fulfilled with that value.
It is important to understand in this case, so I rephrase: if a callback returns a non-Promise, that return value becomes the value of the promise, and the promise is fulfilled.
If the return value v is itself a Promise, then the promise is resolved but not yet fulfilled.
Your case:
allow me to post the functions a,b and c here:
let a = function() {
return new Promise( (resolve, reject) => {
setTimeout(() => resolve(1), 300);
});
}
let b = function() {
return new Promise( (resolve, reject) => {
setTimeout(() => resolve(2), 200);
});
}
let c = function() {
return new Promise( (resolve, reject) => {
setTimeout(() => resolve(3), 100);
});
}
and the implementation
a().then( result => console.log(result))
.then( () => {b().then( result => console.log(result))})
.then( () => {c().then( result => console.log(result))});
Here is what is happening
By adding the curly braces to the arrow function body, we no longer get the automatic return.
This function now returns undefined instead of returning a Promise, which means that the current Promise is fulfilled and next stage in this Promise chain will be invoked with undefined as its input.
So, function a gets invoked, returns a promise, which is, once fulfilled invokes the callback1.
callback 1 returnes undefined so the promise1 is fulfilled and the next .then() invokes the callback2.
The callback2 invokes the b which itself returnes a Promise, but this Promise is not returned by the callback2. The callback2 returns undefined. The Promise2 is fulfilled with undefined and life goes on - Callback3 gets invoked.
At this point b and c are running simultaneously, and because c is 100ms faster than b you get the 1,3,2 order.
Terminology
We say that the promise has been fulfilled if and when the first callback (argument of then method) is called.
And we say that the Promise has been rejected if and when the second callback (argument of then method) is called.
If a Promise is neither fulfilled nor rejected, then it is pending. And once a promise is fulfilled or rejected, we say that it is settled.
If the async code runs normally (and the Promise is fulfilled), then that result is essentially the return value of the code.
If the Promise is fulfilled, then the value is a return value that gets passed to any callback functions registered as the first argument of then().
Promises can also be resolved. It is easy to confuse this resolved state with the fulfilled state or with settled state, but it is not precisely the same as either.
Resolved means that another Promise has been assigned to the value of the current Promise. The current Promise has become associated with, or “locked onto,” another Promise.
We don’t know yet whether the Promise will be fulfilled or rejected, because it is not yet settled. Its fate now depends entirely on what happens to Promise

Returning a Promise inside of a "then" handler causes another unrelated Promise to be resolved with the returned Promise's resolution value

I've been trying to figure this one out and I'm wondering how the resolution value gets passed too getAnswer's then call. First I return the result of add which I think returns a Promise which allows me to use a then call on the then method on getAnswer, but then how does the second return statement get passed to it?
function add(num1, num2) {
return new Promise((resolve, reject) => {
setTimeout(() => {resolve(num1 + num2);}, 500)
});
}
function getAnswer() {
return add(5, 5).then((res) => {
console.log(res);
return new Promise((resolve, reject) => {
resolve("How does this get passed too getAnswer's then function?");
});
});
}
getAnswer().then((res) => {
console.log(res);
})
The Basics:
add returns a Promise -- which is an instance of the Promise object, every instance of Promise has a then method which you can use to observe that promise's resolution.
For chaining purposes, then has been designed in such a way that it returns a Promise itself (so, every then call in JavaScript will always return a new promise). The promise returned by then will be resolved with the return value of its handlers (more on this later).
Now, when you say:
return add(5, 5).then((res) => {
console.log(res);
return new Promise((resolve, reject) => {
resolve("How does this get passed too getAnswer's then function?");
});
});
You are not returning add's result, you are returning the promise that you created by calling then on add's result (this is just standard JS behavior).
Your Question:
but then how does the second return statement get passed to it?
Here is what the then method returns, according to MDN (the parts inside ([]) are my additions):
A Promise in the pending status ([this is what your first return statement is actually returning]). The handler function (onFulfilled or onRejected) gets then called asynchronously ([the handler in your example is the function you've passed to the then inside getAnswer]). After the invocation of the handler function, if the handler function:
returns a value, the promise returned by then gets resolved with the returned value as its value;
throws an error, the promise returned by then gets rejected with the thrown error as its value;
([this is your case -- your second return]) returns an already resolved promise, the promise returned by then gets resolved with that promise's value as its value;
returns an already rejected promise, the promise returned by then gets rejected with that promise's value as its value.
returns another pending promise object, the resolution/rejection of the promise returned by then will be subsequent to the resolution/rejection of the promise returned by the handler. Also, the value of the promise returned by then will be the same as the value of the promise returned by the handler.
Personally, whenever I see a Promise being returned by then's handlers, I just assume -- to simplify the situation for my mind -- that the Promise returned by then originally has been replaced with the Promise that was just returned by one of then's handlers. Of course, this mental mapping is parallel to the actual functionality, AFAIK.
So, to sum it up:
getAnswer returns a promise -- created by add(5, 5).then(...).
you then observe that returned promise using then (getAnswer().then(...)) -- unrelated here, but this call also creates a promise.
it happens that the handler for the observation of the promise returned by the add call (this handler is the function you pass to then in #1) returns a promise as well, and the rules are that if a handler of then returns a promise p, then whenever p is resolved with a value v, the original promise -- created by then -- will be resolved with v as well.
Finally, the handler you passed to the then in #2 to observe the promise returned by getAnswer() will be called with the value v from #3.
Feel free to ask for any clarifications, but before doing so, read this article thoroughly.

Resolving promises from ES6 Arrow Functions

Reading the docs as I understand it in ES6 the meaning of:
foo => someFun(foo);
is equivalent to:
foo => { return someFun(foo); }
I'm returning a new Promise and within that code using arrow functions to invoke the resolve & reject methods, e.g.
return new Promise(function(resolve, reject)
{
someFunThatReturnsAPromise()
.then(data => resolve(data))
.catch(err => reject(err));
});
As such is the code in the then actually,
.then(data => return resolve(data))
If so, does it matter that the result of resolve (of which I'm not sure of the type of value) and should I instead be slightly less terse and write it using {} to prevent the implicit return
.then(data => { resolve(data); })
The resolve function already returns undefined, so it makes absolutely no difference if you implicitly return it with a one-line arrow function or don't return it from a function body at all (since the latter means your function body implicitly returns undefined itself).
Furthermore, since you've wrapped the promise returned by someFunThatReturnsAPromise() in a new promise, there's nothing that handles the return anyway so it wouldn't make any difference even if did return something.
More importantly, the way you've wrapped a promise in a new promise is an anti-pattern. The new Promise() construct is only for dealing with asynchronous processes that aren't already promise based.
Since someFunThatReturnsAPromise() already return a promise, you don't need to wrap it in a new one, simply use the one you got!
For your example that would simply mean returning it:
return someFunThatReturnsAPromise()
If you want to do some processing of the data, such as only returning a part of the data (the status property in the below example), you do that in a then callback:
return someFunThatReturnsAPromise().then(data => data.status)
When you return in a then callback, it will in turn return a new promise that gets resolved with the data you returned (unless you returned another promise, in which case it will resolve when that promise resolves).
This is how promises are designed to work, by chaining the asynchronous processes and their results.
If you just want to return data, and reject incase of an error then you don't need a then()
return new Promise(function(resolve, reject)
{
someFunThatReturnsAPromise()
.then(data => resolve(data))
.catch(err => reject(err));
});
would be equivalent to
return someFunThatReturnsAPromise()
unless you want to do some processing on data

Categories

Resources