I'm trying to make sense of the idea that promises that return another promise become the value of the return. That's what I read in the Q docs on the wiki. https://github.com/kriskowal/q#tutorial
Its the ideal situation, as I'm using q-io/http which uses a promise to make the request. However, the function returns the value of the body in a new promise.
Rather than nesting the rest of my code inside my first function. I want to be notified when the nested promise is complete. However, because of scope, I can't seem to do it. But I keep reading that my outer function should become the value of the inner promise. Am I missing something?
Ex.
module.exports = function (obj) {
var getFiles = HTTP.request(obj);
getFiles
.then(function(res) {
return res.body.read()
});
return getFiles;
};
I want to be notified when res.body.read() fulfills its promise using Q.all(), but I don't know how to get that value. I feel like getFiles should become that inner promise. Right?
I feel like getFiles should become that inner promise. Right?
No. A promise won't change it's value. However, the .then method does return a new promise that will be resolved with the result of the "inner promise" read method (which will be called when getFiles is resolved).
You can shorten your code to
module.exports = function (obj) {
return HTTP.request(obj).then(function(res) {
return res.body.read()
});
};
Related
I would like to get a deeper understanding of how Promises work internally.
Therefore I have some sample code:
var p1 = new Promise(
function(resolve, reject) {
window.setTimeout(
function() {
resolve('res called')
}, 2000);
});
var p2 = new Promise(
function(resolve, reject) {
window.setTimeout(
function() {
resolve('res called')
}, 2000);
});
function chainPromises() {
return p1.then(function(val) {
console.log("p1");
return p2.then(function(val) {
console.log("p2");
return val;
});
});
}
chainPromises().then(function(val) {
console.log(val);
});
Here a link to execute this code.
As you would predict, first p1 is resolved, afterwards p2 and in the end the final then prints the resolv value.
But the API ref states the following:
"then" returns a new promise equivalent to the value you return from
onFulfilled/onRejected after being passed through Promise.resolve
So it would be interesting to know WHEN exactly the "then" function is executed?
Because the final "then" in the code is chained to the chainPromises(), I first thought that
it would execute after the function chainPromises() returns something (in this case another promise).
If this would have been the case the "val" of the final "then" function would be the returned promise.
But instead, the final "then" waits until all promises inside the first "then" which are returned have been resolved.
This absolutely makes sense because in this way, the "then" functions can be stacked, but
I do not really get how this is done, since the API spec. does not really cover what "then" returns and when the "then" functions is executed.
Or in other words, why does the final "then" function wait until all the Promises are resolved inside the chainPromises() function instead of just waiting for the first returned object as the API doc says.
I hope I could make clear what I mean.. :)
About Promise resolution
The thing you're witnessing here is called recursive thenable resolution. The promise resolution process in the Promises/A+ specification contains the following clause:
onFulfilled or onRejected returns a value x, run the Promise Resolution Procedure [[Resolve]](promise2, x)
The ES6 promise specification (promises unwrapping) contains a similar clause.
This mandates that when a resolve operation occurs: either in the promise constructor, by calling Promise.resolve or in your case in a then chain a promise implementation must recursively unwrap the returned value if it is a promise.
In practice
This means that if onFulfilled (the then) returns a value, try to "resolve" the promise value yourself thus recursively waiting for the entire chain.
This means the following:
promiseReturning().then(function(){
alert(1);
return foo(); // foo returns a promise
}).then(function(){
alert(2); // will only run after the ENTIRE chain of `foo` resolved
// if foo OR ANY PART OF THE CHAIN rejects and it is not handled this
// will not run
});
So for example:
promiseReturning().then(function(){
alert(1);
return Promise.resolve().then(function(){ throw Error(); });
}).then(function(){
alert("This will never run");
});
And that:
promiseReturning().then(function(){
alert(1);
return Promise.resolve().then(function(){ return delay(2000); });
}).then(function(){
alert("This will only run after 2000 ms");
});
Is it a good idea?
It's been the topic of much debate in the promises specification process a second chain method that does not exhibit this behavior was discussed but decided against (still available in Chrome, but will be removed soon). You can read about the whole debate in this esdiscuss thread. This behavior is for pragmatic reasons so you wouldn't have to manually do it.
In other languages
It's worth mentioning that other languages do not do this, neither futures in Scala or tasks in C# have this property. For example in C# you'd have to call Task.Unwrap on a task in order to wait for its chain to resolve.
Let's start with an easy perspective: "chainPromises" returns a promise, so you could look at it this way:
// Do all internal promises
var cp = chainPromises();
// After everything is finished you execute the final "then".
cp.then(function(val) {
console.log(val);
});
Generally speaking, when returning a promise from within a "then" clause, the "then" function of the encapsulating promise will be marked as finished only after the internal "then" has finished.
So, if "a" is a promise, and "b" is a promise:
// "a"'s "then" function will only be marked as finished after "b"'s "then" function has finished.
var c = a.then(function () {
return b.then(function () {
console.log("B!");
};
};
// c is a promise, since "then" always returns a promise.
c.then(function() {
console.log("Done!");
};
So the output will be:
B!
Done!
Notice btw, that if you don't "return" the internal promise, this will not be the case:
// "a"'s "then" function will only be marked as finished without waiting for "b"'s "then" to finish.
var c = a.then(function () {
// Notice we're just calling b.then, and don't "return" it.
b.then(function () {
console.log("B!");
};
};
// c is a promise, since "then" always returns a promise.
c.then(function() {
console.log("Done!");
};
Here we can't know what would be outputted first. It could be either "B!" or "Done!".
Please check the below example regarding how promises works:
The Promise object represents the eventual completion (or failure) of an asynchronous operation, and its resulting value.
console.log('person1: shoe ticket');
console.log('person2: shoe ticket');
const promiseGirlFriendBringingTickets = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('ticket');
}, 3000);
});
promiseGirlFriendBringingTickets.then((t) => {
console.log(`person3: show ${t}`);
})
console.log('person4: shoe ticket');
console.log('person5: shoe ticket');
Promise then return promise object, not promise's resolved value. I forked your JsFiddle, and added some of mine try this.
promise.then is executed right after that promise object is resolved.
I do not know how this is done in actual promises libraries, but I was able to re-create this functionality in the following way:
1) each promise has a waitingPromises property;
2) then method returns a new promise, and the original promise's waitingPromises property points to the new promise.
In this way, the chain of .then()s creates a structure that is similar to a linked list or rather a tree (each promise can have several waiting promises). A promise can be resolved only after its 'parent' promise has been resolved. The .then method itself is executed immediately, but the corresponding promise that it creates is resolved only later.
I am not sure this is a good explanation and would love to learn about other possible approaches.
Normally code is synchronous - one statement executes like (fileopen) and there is a guarantee that the next statement will execute immediately afterwards like filewrite()
but in asynchronous operations like nodejs, you should assume that
you have no idea when the operation will complete.
You can't even assume that just because you send out one request first, and another request second, that they will return in that order
Callbacks are the standard way of handling asynchrnous code in JavaScript
but promises are the best way to handle asynchronous code.
This is because callbacks make error handling difficult, and lead to ugly nested code.
which user and programmer not readble easily so promises is the way
You can think of Promise as a wrapper on some background task. It takes in a function which needs to be executed in the background.
The most appropriate place to use a promise is where some code is dependent on some background processing and it needs to know the status of the background task which was executed. For that, the background task itself accepts two callback resolve and reject in order to convey its status to the code which is dependent on it. In layman terms, this code is the one behind it in the promise chain.
When a background task invokes resolve callback with some parameter. it's marking the background operation successful and passing the result of the background operation to the next then block which will be executed next. and if it calls reject, marking it as unsuccessful then the first catch block will be executed.
In your custom promise, you can pass an error obj to the reject callback so that next catch block is aware of the error happened in the background task.
I am trying to create a new javascript Promise, and in function I pass to the new Promise(func) I would like to have access to the promise object I created to store and use later to resolve when something has occurred, rather than call functions to do the work from within the promise function.
I have tried:
let promise = new Promise((resolve, reject) => {
this._setupPromise = { promise, resolve, reject };
});
But of course the "promise" variable is not yet set, so this._setupPromise.promise is undefined.
I can change it like this to add the promise to the object outside of the new Promise, but it just doesn't feel right since it could run before the Promise constructor function:
this._setupPromise = {};
let promise = new Promise((resolve, reject) => {
this._setupPromise.resolve = resolve;
this._setupPromise.reject = reject;
});
this._setupPromise.promise = promise
Is there any good solution to my delimma?
For anyone wondering why I would resolve/reject the Promise outside of calling it from within the Promise constructor function, I am optionally promisifying some legacy code, and to avoid a massive refactor of some existing use cases, it helps me resolve the promises elsewhere optionally.
Making my comment into an answer (and adding more explanation) since it actually was the answer you were looking for:
Your second code block is the way to do it. The promise variable itself does not have a value until the executor has returned and then the constructor has returned so you can't assign it to something else until after the executor and the promise constructor are done.
Since you don't have any asynchronous code inside the executor function, things will execute sequentially so this doesn't look like it would be a problem.
You may find that using a Deferred object (which just encapsulates the saving of the resolve and reject functions) as shown here is a bit cleaner and more reusable. Then, you could just do:
this._deferred = new Deferred();
And, later, you can do any of these:
this._deferred.resolve(...);
this._deferred.reject(...);
this._deferred.then(...);
this._deferred.catch(...);
let p = this._deferred.promise;
If you described the overall problem you're trying to solve, we might be able to present a whole different approach to solving the actual problem.
Question was answered by jfriend00 and Jaramanda X in the comments.
My second code block was the correct way to do this in my case because the function passed to the Promise constructor is executed before the Promise constructor exits.
That means in my case with no asynchronous code in the function, I can safely assign the promise reference afterwards.
The following code contains two kinds of promise chain, seems they'r equivalent, but I don't understand why they are equivalent. I think of it like 2*(3+4) = 2*3+4, which is not correct.
// example1
runAsync1()
.then(function(data1){
return runAsync2()
.then(function(data2){
return runAsync3();
})
})
.then(function(data3){
console.log(data3);
});
// example 2
runAsync1()
.then(function(data1){
return runAsync2();
}).then(function(data2){
return runAsync3();
}).then(function(data3){
console.log(data3);
});
Maybe some braces would help you understand this a little better. (NOTE: this is exactly the same thing as you had except with an extra set of braces on the return)
// example1
runAsync1()
.then(function(data1){
return (
runAsync2()
.then(function(data2){
return runAsync3();
})
)
})
.then(function(data3){
console.log(data3);
});
So what is happening here,
.then is called on runAsynch1()
.then is then called on runAsynch2() which returns runAsynch3() (this return carries on all the way down the chain of returns)
finally .then is called on the returned runAsynch3()
As you can see, this is exactly the same process as what happens in example 2
// example 2
runAsync1()
.then(function(data1){
return runAsync2();
}).then(function(data2){
return runAsync3();
}).then(function(data3){
console.log(data3);
});
It's a little bit implementation-specific, but the magic, regardless of the specifics is in the then.
Then does a couple of things.
The TL;DR is that then subscribes to returned promise chains, but below are examples closer to the guts of a promise.
The first thing is:
"Is the promise still pending? Then schedule these callbacks for later; otherwise, schedule this callback to run on the next tick (setTimeout(handle, 0)). Return a new promise that resolves/rejects to the eventual value."
// basically accurate-ish
then (onSuccess, onError) {
return new Promise((resolveNext, rejectNext) => {
if (myPromiseIsDone) {
// I already have the value; run the next step ASAP
// this is ugly, but hopefully it proves a point
runOnNextTick(onSuccess, onError, promiseResult, resolveNext, rejectNext);
} else {
// I don't have a result yet; come back when it's ready
scheduleWhenDone(onSuccess, onError, resolveNext, rejectNext);
}
});
}
The second is where your answer lies:
"Run the handler. Get the return value from the callback passed to then. Is the return value a Thenable object (has a then method)? Then call then and pass in the resolve/reject functions that control my promise... otherwise, resolve/reject accordingly, based on whether it throws or returns."
// entirely subjective and implementation-specific,
// but the algorithm is almost spec-compliant
handleSuccess (onSuccess, resolveNext, rejectNext, value) {
if (!onSuccess) {
// if they didn't give me a `then(callback)`,
// just pass the value to the next promise
resolveNext(value);
return;
}
try {
// I'm running the `then(callback)` here
const result = onSuccess(value);
if (hasThenMethod(result)) {
// it's promise-like, subscribe
result.then(resolveNext, rejectNext);
} else {
resolveNext(result);
}
} catch (err) {
// something blew up, while trying to succeed, so fail
rejectNext(err);
}
}
Reject looks similar.
So the outer then subscribes to the inner then.
If you ever wanted to get into functional programming, the ES6 Promise is almost a monad.
The difference is that a monad would force you to have a different method, to tell it to chain to the returned promise, rather than doing it automatically.
then is basically the same as map on arrays. You call then, pass it a function that gets the value and returns a new promise with the transformed value.
So a monadic promise might be one that has map and chain, or then and chain, where chain does almost exactly the same thing but says "hey, then, this callback is going to return a promise; subscribe to that one, so that you flatten it out, rather than returning a promise of a promise of a value".
That's almost all it would take to be a monad.
Hope that all helps.
find is a function that returns a promise that resolves to a value, but also has data on the promise object itself. A practical use case is when find() returns a dbQueryObject that can be used elsewhere, whereas await find() resolves with databaseResults. eg:
function find () {
var results = new Promise(/* resolves with databaseResults */)
Object.assign(results, new dbQueryClass)
return results
}
I can wrap find with a function to provide helpers like this,
function findPage (page) {
return find().skip(page*20).limit(20)
}
and use it like findPage().select('_id') to get the query object or await findPage().select('_id') to get the resolved value (returns something similar to find()).
However, if I wrap find with a promise like this,
async function findSomething() {
var someArgs = await promise1()
if (someArgs) return find(someArgs)
return find()
}
How do I get the value of find() itself outside of findSomething? I need promise1 to resolve, but I need find() to not resolve. find() is a plain object AND a thenable, depending on if you resolve it or not, but resolving findSomething() will automatically resolve the returned value. How do I return it such that it doesn't resolve?
My constraint is that I cannot modify the library that provides find() to not return a thenable object.
I don't see what would "usually" be an antipattern here. You can return or await any promise, thenable or plain value in an async function, just as you can Promise.resolve them or return them from a then callback. There is nothing unusual about this, that's just how it is done.
If you want to be explicit about returning a promise, instead of relying on thenable assimilation, you can always call .exec() on your mongoose query and it will get you a "real" promise.
As stated here https://stackoverflow.com/a/22724984/704894, it's impossible to have Promise<Promise<value>> because when you return a Promise inside .then handler, it gets automatically resolved (unwrapped).
You'd have to use Promise<Wrapper<Promise>> to bypass this limitation.
Sidenote for functional programming folks: .then is both map and flatMap in Haskell terms.
I have a question about attaching callback functions to promises in AngularJS.
Suppose I have a service with a function that returns a promise. I make a call to this function and store the promise locally. Then I define a callback function on the promise.
var promise = TestService.get();
console.log('We have a promise!');
promise.then(function (result){
console.log('Here is the result:'+result);
});
In this case, we have a potentially risky situation. If the promise is resolved before we get to promise.then(..., the result is not outputted to the console (until the next digest cycle).
Alternatively, I could write the above code like this:
TestService.get().then(function (result){
console.log('Here is the result:'+result);
});
My question:
Has the risk been mitigated in the second example? And if not, how can I make sure that the promise does not resolve before I have attached a callback?
A slightly more elaborate answer than yes/no would be much appreciated :)
The behavior you are describing does not occur, that can be seen through a simple example. Here we have a simple promise factory which returns a promise which resolves immediately.
'use strict';
var make = function() {
return new Promise(function(resolve, reject) {
resolve(2);
});
};
Then we create a new promise and assign it to a variable
var prom = make();
We can call .then on it as many times as we want. This is because promises are immutable, we don't change the original value by chaining methods on it.
prom.then(a => console.log(a));
// 2
prom.then(a => console.log(a));
// 2
Suppose I have a service with a function that returns a promise. I make a call to this function and store the promise locally. Then I define a callback function on the promise.
No, you are not attaching a callback. When you call the then method you are doing something called promise chaining. Each call to then returns a new promise object that will resolve to the value returned by the previous promise.
For example;
var promise1 = TestService.get();
var promise2 = promise1.then(function(value) {
console.log('service resolved: '+value);
return "Hello World";
});
var promise3 = promise2.then(function(value) {
console.log(value);
});
promise3.then(function(value) {
console.log(value);
});
The above example will output the following.
**some value from TestService**
Hello World
undefined
We don't know who originally resolve the value for the first promise. All we know is that the service returned a promise. From that moment on we can chain the promises by adding more calls to then.
In this case, we have a potentially risky situation. If the promise is resolved before we get to promise.then(..., the result is not outputted to the console (until the next digest cycle).
No, it does not matter when or what digest the promise is resolved. A promise can have it's then method called multiple times even after being resolved. It will continue to resolve to the value as long as it has not been rejected. The decision to resolve or reject a promise is outside the scope of the success or failure callbacks.
You can create a promise, resolve it to a value, wait several digests and add a handler to then and it will still work as expected.
Has the risk been mitigated in the second example? And if not, how can I make sure that the promise does not resolve before I have attached a callback?
Think of promises as containers. They are going to hold the value you expect, and you have to call then to get it. If for what ever reason the value is unavailable you can find out why by using the error callback. The when aspect of promises is purely an asynchronize issue, and the idea is for promises to hide those issues.
JavaScript is not multithreaded, your asynchronous AJAX call isn't actually made by the browser until your code returns.
var promise = TestService.get();
for (var i= 0;i<100000;i++){
console.log(i)
}
console.log('We have a promise!');
promise.then(function (result){
console.log('Here is the result:'+result);
});
Watch this with the network analyzer.