I'm reading the Async & Performance book of the YDKJS series and am having trouble wrapping my head around the revealing constructor pattern.
Here's the example the book gives:
function foo(x) {
// start doing something that could take a while
// construct and return a promise
return new Promise( function(resolve,reject){
// eventually, call `resolve(..)` or `reject(..)`,
// which are the resolution callbacks for
// the promise.
} );
}
var p = foo( 42 );
function bar(fooPromise) {
// listen for `foo(..)` to complete
fooPromise.then(
function(){
// `foo(..)` has now finished, so
// do `bar(..)`'s task
},
function(){
// oops, something went wrong in `foo(..)`
}
);
}
bar( p );
I have two questions:
I think the intention is not to expose the resolve and reject logic to the outside, which creates a good separation of concern between the promise logic and what happens next with .then() in the function (in this case bar()) that "listens" to the Promise. Am I on track here?
The example foo() confuses me. In the comment // start doing something that could take a while, what exactly is this? Is this where your async call would be? Shouldn't it be inside the function in the return statement? I don't understand how this would work otherwise.
I think the intention is not to expose the resolve and reject logic to the outside, which creates a good separation of concern
Yes, that and the difficulty of catching exceptions in the deferred pattern, an alternative way to expose the resolvers only to the function that creates the task but not those that consume the result.
The example foo() confuses me. In the comment // start doing something that could take a while, what exactly is this? Is this where your async call would be?
Yes, that's what they meant.
Shouldn't it be inside the function in the return statement?
Yes, indeed it should be. A specific example might be
function delay(x) {
return new Promise(function(resolve) { // construct and return a promise
setTimeout(function() { // start doing something that could take a while
resolve(); // eventually, call one of the resolution callbacks
}, x);
});
}
It's of course possible that starting the task and waiting for its result are two separate statements, so they could in theory be put apart:
function ajax(x) {
var xhr = new XMLHttpRequest();
xhr.open("GET", x);
xhr.send(); // start doing something that could take a while
return new Promise(function(resolve, reject) { // construct and return a promise
xhr.onload = resolve;
xhr.onerror = reject; // eventually, call one of the resolution callbacks
});
}
but that is a bad practise, as when new, open or send throw you would not get a rejected promise back but an exception. So everything from var xhr = … should be inside the promise constructor callback.
For 2., in general and without further details, yes, you are correct; the resolver function passed to Promise constructor executes immediately. One exception would be use of async/await, though async/await does not appear at JavaScript at Question.
Related
I have abstraction:
function fetchDataFromAPI() {
const url = `https://api...`
return fetch(url).then(response => response.json())
}
I want to use it in my other piece of code like:
if(something){
const data = fetchDataFromAPI()
return data
}
if I console.log data what I get is resolved pending promise
Promise {<pending>}
__proto__: Promise
[[PromiseStatus]]: "resolved"
[[PromiseValue]]: Object
How do I get that Object in data instead of Promise?
You can not. Here is why:
Promise is a language construct that makes JavaScript engine to continue to execute the code without waiting the return of inner function, also known as the executor function. A promise always run inside the event loop.
var p = new Promise(function(resolve, reject) {
setTimeout(function() {
resolve('foo');
}, 300);
});
console.log(p);
Basically a promise is a glorified syntactic sugar for a callback. We will see how but first lets have a more realistic code:
function someApiCall(){
return new Promise(function(resolve, reject){
setTimeout(()=>{
resolve('Hello');
})
})
}
let data = someApiCall();
console.log(data);
This is a so-called asynchronous code, when JavaScript engine executes it, someApiCall immediately returns a result, in this case pending promise:
> Promise {<pending>}
If you pay attention to the executor, you will see we needed to pass resolve and reject arguments aka callbacks. Yes, they are callbacks required by the language construct. When either of them called, promise will change its state and hence be settled. We don't call it resolved because resolving implies successful execution but a function also can error out.
How do we get the data? Well we need more callbacks, which will be called by the executor function once the promise is settled:
var p = new Promise(function(resolve, reject) {
setTimeout(function() {
resolve('foo');
}, 300);
});
p.then((result) => {
console.log(result); // foo
}).catch((err) => {
console.log(err);
});
Why we need to pass separate callbacks? Because one will be fed to the resolve, and the other to the reject. Then callback will be called by the resolve function, the catch callback by the reject function.
Javascript engine will execute these callbacks later on its leisure, for a regular function it means when the event loop is cleared, for timeout when the time is up.
Now to answer your question, how do we get data out from a promise. Well we can't.
If you look closely, you will see we don't really get the data out but keep feeding callbacks. There is no getting data out, but passing callbacks in.
p.then((result) => {
console.log(result);
}).catch((err) => {
console.log(err);
});
Some say use await:
async function() {
let result = await p;
}
But there is a catch. We have to or wrap it in async function. Always. Why? Because Async/await is another level of abstraction or syntactic sugar, whichever you prefer, on top of promise api. That is why we can not use await directly but always wrap it in async statement.
To sum up, when we use promise or async/await we need to follow certain convention and write terse code with closely knitted callbacks. Either javascript engine or transpilers like babeljs or typescript converts these code to regular javascript to be run.
I can understand your confusion because people keep saying getting data out when talking about promises, but we don't get any data out but pass callback to be executed when the data is ready.
Hope everything is clear now.
No, you cannot without using promises or async/await etc because calling a REST API is an asynchronous operation and is non blocking.
When you make a call to a REST API, the code shouldn't wait until the API returns a value because it may take a lot of time, making program non-responsive, thus by design making a network request is categorized as an asynchronous operation.
To avoid async/await, you'll need to use another .then:
if (something) {
return fetchDataFromAPI()
.then((data) => data /* you can console.log(data) here */)
}
Below is a simplification of my code, I'm basicly running a function, that creates a Promise inside the function and returns it. For some reason though, testing with console.time(), it would appear that the code is actually blocking. The x.root function takes roughly 200ms to run and both console.time() tests give pretty much 200ms. Now if I did the age old trick of wrapping the function in setTimeout, the problem disappears, but I'd like to know what I'm doing wrong here?
I'd really prefer being able to create, resolve and reject the promises inside my helper function and then just call my function followed by then and catch without having to create Promises on an earlier level. What's the malfunction here?
parseroot = function(params) {
return new Promise(function(resolve, reject) {
try {
var parsed_html = x.root(params);
x.replacecontents(params.target, parsed_html);
resolve(true);
}
catch(e) {
reject(e);
}
});
}
console.time("Test 1");
console.time("Test 2");
var el = document.querySelector("#custom-element");
el.parseroot({
section:"list",
target: "#list-container",
}).then(function(response) {
console.info("searchresult > list() success");
console.timeEnd("Test 2");
});
console.timeEnd("Test 1");
Promises don't turn synchronous code into asynchronous code.
If the function you pass to Promise blocks, then the promise will block too.
Background
I am trying to learn promises, and I have a promise chain I want to improve on.
Problem
While learning how to chain promises, I fail to see why anyone would rather return a promise instead of returning it's value.
Take the following example, which uses promise chaining:
let myObj = new MyClass();
myObj.getInfo()
.then(result => writeOutput(FILE_NAME, result))
.then(console.log(FILE_NAME + " complete"))
.catch(error => console.error(error));
class MyClass{
getInfo() {
return new Promise(function(fulfil, reject) {
fulfill("I like bananas");
});
}
Here I have to chain 2 times. But if I were to directly return the result from the method getInfo() instead of returning a Promise I could potentially do something like the following:
let myObj = new MyClass();
let str = myObj.getInfo();
writeOutput(FILE_NAME, str)
.then(console.log(FILE_NAME + " complete"))
.catch(error => console.error(error));
Questions
So as you can see I am a little confused.
Given that getInfo() is in fact async, is it possible to achieve a similar code to the one in my second code sample?
If it were possible, would it be a good idea? How would you do it?
You can only return a value from some function if that value is immediately available when that function is called (on the same tick of the event loop). Remember that return is synchronous.
If it is not available right away then you can only return a promise (or you can use a callback but here you are specifically asking about promises).
For a more detailed explanation see this answer that I wrote some time ago to a question asking on how to return a result of an AJAX call from some function. I explained why you cannot return the value but you can return a promise:
jQuery: Return data after ajax call success
Here is another related answer - it got downvoted for some reason but I think it explains a similar issue that you're asking about her:
Return value in function from a promise block
I fail to see why anyone would rather return a promise instead of returning it's value.
Because you don't have the value yet.
Given that getInfo() is in fact async, is it possible to achieve a similar code to the one in my second code sample?
If it's asynchronous, it must return a promise.
A syntax that avoids then calls (but still uses and produces promises) is made possible by async/await:
async function writeInfo(FILE_NAME) {
const myObj = new MyClass();
try {
const str = await myObj.getInfo();
await writeOutput(FILE_NAME, str);
console.log(FILE_NAME + " complete");
} catch (error) {
console.error(error);
}
}
writeInfo("…");
The purpose of a promise is to say: "The data will be there sometime, just continue with your coding for now", so that your page won't get stuck for example. Basically you are using Promises for example to load something from the server.
Another way of looking at the first question ("why would anyone..."):
When you call .then or .catch on a promise, the pending promise returned from the call is appended to the end of an existing promise chain. (Allowing the "existing chain" might only contain one promise).
When you resolve (not "fulfill", you can't fulfill a promise with a promise) a promise with a promise, the promise used in resolution is inserted at the head of what remains of the promise chain.
The promise used in resolution must be fulfilled with a value before the next .then or .catch clause in the chain is called.
When using Promises, why can't triggers for resolve and reject be defined elsewhere in the codebase?
I don't understand why resolve and reject logic should be localized where the promise is declared. Is this an oversight, or is there a benefit to mandating the executor parameter?
I believe the executor function should be optional, and that its existence should determine whether the promise encapsulates resolution or not. The promise would be much more extensible without such mandates, since you don't have to initiate async right away. The promise should also be resettable. It's a 1 shot switch, 1 or 0, resolve() or reject(). There are a multitude of parallel and sequential outcomes that can be attached: promise.then(parallel1) and promise.then(parallel2) and also promise.then(seq1).then(seq2) but reference-privileged players cannot resolve/reject INTO the switch
You can construct a tree of outcomes at a later time, but you can't alter them, nor can you alter the roots (input triggers)
Honestly, the tree of sequential outcomes should be edittable as well.. say you want to splice out one step and do something else instead, after you've declared many promise chains. It doesn't make sense to reconstruct the promise and every sequential function, especially since you can't even reject or destroy the promise either...
This is called the revealing constructor pattern coined by Domenic.
Basically, the idea is to give you access to parts of an object while that object is not fully constructed yet. Quoting Domenic:
I call this the revealing constructor pattern because the Promise constructor is revealing its internal capabilities, but only to the code that constructs the promise in question. The ability to resolve or reject the promise is only revealed to the constructing code, and is crucially not revealed to anyone using the promise. So if we hand off p to another consumer, say
The past
Initially, promises worked with deferred objects, this is true in the Twisted promises JavaScript promises originated in. This is still true (but often deprecated) in older implementations like Angular's $q, Q, jQuery and old versions of bluebird.
The API went something like:
var d = Deferred();
d.resolve();
d.reject();
d.promise; // the actual promise
It worked, but it had a problem. Deferreds and the promise constructor are typically used for converting non-promise APIs to promises. There is a "famous" problem in JavaScript called Zalgo - basically, it means that an API must be synchronous or asynchronous but never both at once.
The thing is - with deferreds it's possible to do something like:
function request(param) {
var d = Deferred();
var options = JSON.parse(param);
d.ajax(function(err, value) {
if(err) d.reject(err);
else d.resolve(value);
});
}
There is a hidden subtle bug here - if param is not a valid JSON this function throws synchronously, meaning that I have to wrap every promise returning function in both a } catch (e) { and a .catch(e => to catch all errors.
The promise constructor catches such exceptions and converts them to rejections which means you never have to worry about synchronous exceptions vs asynchronous ones with promises. (It guards you on the other side by always executing then callbacks "in the next tick").
In addition, it also required an extra type every developer has to learn about where the promise constructor does not which is pretty nice.
FYI, if you're dying to use the deferred interface rather than the Promise executor interface despite all the good reasons against the deferred interface, you can code one trivially once and then use it everywhere (personally I think it's a bad idea to code this way, but your volume of questions on this topic suggests you think differently, so here it is):
function Deferred() {
var self = this;
var p = this.promise = new Promise(function(resolve, reject) {
self.resolve = resolve;
self.reject = reject;
});
this.then = p.then.bind(p);
this.catch = p.catch.bind(p);
if (p.finally) {
this.finally = p.finally.bind(p);
}
}
Now, you can use the interface you seem to be asking for:
var d = new Deferred();
d.resolve();
d.reject();
d.promise; // the actual promise
d.then(...) // can use .then() on either the Deferred or the Promise
d.promise.then(...)
Here a slightly more compact ES6 version:
function Deferred() {
const p = this.promise = new Promise((resolve, reject) => {
this.resolve = resolve;
this.reject = reject;
});
this.then = p.then.bind(p);
this.catch = p.catch.bind(p);
if (p.finally) {
this.finally = p.finally.bind(p);
}
}
Or, you can do what you asked for in your question using this Deferred() constructor:
var request = new Deferred();
request.resolve();
request.then(handleSuccess, handleError);
But, it has the downsides pointed out by Benjamin and is not considered the best way to code promises.
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.