Order in Promise/Async/Await (Interview Question) - javascript

Question:
new Promise((resolve) => {
console.log(1)
resolve()
}).then(async () => {
console.log(2)
}).then(async () => {
console.log(3)
})
new Promise((resolve) => {
console.log('a')
resolve()
}).then(() => {
console.log('b')
}).then(() => {
console.log('c')
}).then(() => {
console.log('d')
}).then(() => {
console.log('e')
})
Answer:
1
a
2
b
c
d
3
e
But I think answer is.... 1 a 2 b 3 c d e
Please help to share how to think to get answer detailed. Thanks.

First I would explain that nobody should ever rely on precise timing between two separate promise chains. They run independently of one another and as soon as you insert any real world asynchronous operations in either of those promise chains (which all real-world programming would contain), then the timing of each chain is entirely unpredictable vs. the other.
Instead the timing in real code depends upon the timing of the asynchronous operations, not on anything else. Imagine that each of the steps in this promise chain was reading a file or doing some random delay. Those are entirely unpredictable operations so which chain does what first depends upon the timing of the actual asynchronous operations, not on what is shown in this example.
So, trying to dissect the details of exactly when each item goes into the promise job queue and when it gets serviced is a complete waste of programming time and not useful in any real programming problem.
Further, if you really need a specific ordering of operations, then you don't program with two independent promise chains. Instead, you use promise flow-of-control tools (like chaining everything into one chain or using Promise.all(), Promise.race(), etc...) to guide the execution/completion order into exactly what you want it to be regardless of the detailed inner workings of the promise implementation.
Then, I would explain the basics of how the promise queue works by walking through the first two links of one of the promise chains just to show that I understand how a promise gets resolved, gets added to the promise queue and then, when control is about to return to the event loop, the oldest item in the promise queue gets to run and call its .then() or .catch() handlers. This is just to illustrated that you understand the basics of how promises are scheduled and that they get serviced in LIFO order from their own job queue and before most other things in the event loop.
Then, I would explain that a few years ago, the spec was changed for some promise steps in the interest of improving performance and a JS engine before or after that spec change would likely generate different results for something like then. Yet another reason why you shouldn't rely on that level of implementation detail.
If the interviewer insisted on me trying to explain the precise order in this problem and wouldn't listen to my reasoning why that's a pointless exercise, even after hearing my explanation for how I'd code a real world situation where execution order does matter, then unless this was just some really junior interviewer trying to be clever (and outsmarting themselves), I'd have to conclude this is not a good place to work. No senior developer should insist that this is a super valuable or practical exercise beyond showing that you have a basic understanding of how the promise job queue works.

Related

Are there promise library with serial and resolution without async-await?

The inconvenience I have is that there is no way, to my knowledge, using built-in Promise, to resolve a Promise within a synchronous block.
Specifically, the following code
var o = {};
function set(index, value) {
console.log(`setting ${index} to ${o.index = value}`);
}
Promise.resolve().then(()=>set('a', 1)).then(()=>set('b',2))
Promise.resolve().then(()=>set('c', 1)).then(()=>set('d',2))
console.log(`a is ${o.a}`);
Outputs :
a is undefined
setting a to 1
setting c to 1
setting b to 2
setting d to 2
Are there Promise like lib whose Promise would yield the following outputs:
setting a to 1
setting b to 2
setting c to 1
setting d to 2
a is 1
Obviously, no need to resort to Promises in the example above, but in my use case, setting 'a' leads to a pretreatment which only needs to be done once, whereas 'b' can be set multiple times, and is used within the same synchronous block it is set (no freedom on that).
I've looked up bluebird, and I have no clue how their promises work internally, but they seem to embrace using only promise chains.
Q Promise might be what I'm looking for, I'm not sure.
More generally, it feels daunting scouring the docs of the many Promise librairies out there querying some niche, depreciated need with likely the wrong keywords and concepts in mind.
This is definitely a case of ProblemXY where X could be solved in a variety of ways without Promises, for example by synchronous initializers, but I feel problem Y is interesting in and of itself (and likely a duplicate), so I'm still asking.
I'll get around giving problem X its own question, but long story short, I'd love to use, sometimes within a single js synchronous execution block, the expressive power of promises to pull values instead of pushing them and to flatten callbacks and try-catch pyramids.
Edit:
To clarify what I'm curious about, the way I would build the Promiselike with the desired properties is as follow :
let f = myPasync(function*(){ //equivalent to async function declaration
v = yield myPAwait(myPromiseInstance); //equivalent of v = await myPromiseInstance;
})
let pa = new myP( *(resolve, reject)=>{} ) //equivalent to new Promise((resolve, reject)=>{}) ; for simplicity, resolve and reject can be naked properties of pa
pa.myPthen((*()=>{})()) //equivalent to pa.then((v)=>{})
And then, instead of dynamically iterating over a task queue every tick, pushing thens and awaits of newly resolved promised to that queue in a FIFO manner,
I would push to the task queue in a LIFO manner and iterate over it upon any myP related function call.
So for example, when a promise is resolved, every routine awaiting it will resume before anything else, and in particular before the rest of the routine resolving the promise.
Other example when a routine awaits a promise, if that promise is already resolved, the routine is immediately resumed instead of letting other execute.

What happens first: setTimeout 0 or await Promise.resolve?

I'm seeing this behavior in Node and Chrome:
setTimeout(()=>{ console.log('timeout') }, 0)
Promise.resolve().then(()=>{ console.log('promise') })
console.log('sync')
// output order:
// sync
// promise
// timeout
My question is, is this consistent behavior? I.e, according to spec, does a then or await on a memoized/already resolved promise always fire before setTimeout(fn, 0)?
I want to use this in something like the following, returning one thing if I have a memoized result in my promise and another if not:
// somewhere during object initialization
this.resultingPromise = expensiveAsyncFunction()
// in a method called frequently
Promise.race([
new Promise(resolve => setTimeout(() => resolve('default'), 0)),
this.resultingPromise
])
Promise.resolve will schedule a microtask while setTimeout schedule a macrotask. And the microtasks will run before running the next macrotask.
More information about event loop in general: https://www.youtube.com/watch?v=8aGhZQkoFbQ
More technical details about events loop: https://www.youtube.com/watch?v=cCOL7MC4Pl0
so you have 2 async waiting States, but notice that one of them is constant and one is changing (variable). The timeout is set in an XML variable aside while the promise could took forever. If I understood your question quite well, when you have something you rely on take too long and something too short, unless you have a constant applied on one of them like the timeout, then one might end up running shorter unexpectedly (!) Be prepared for that and instead use monolithic structure from code security reasons and not performance.
There's no guarantee that one will be before the other. If you want to guarantee the order of execution - use Promises.
From my understanding Promise has a higher priority in the call stack than setTimeout, and of course synchronous code block will be the first to be executed. In that case, yes the observed behaviour above (in the order of synchronous code block, promise.resolve, and setTimeout 0) should be consistent.

Should I always return promises in all functions in JavaScript? [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 5 years ago.
Improve this question
I am thinking could it be a good approach to always return promises in functions in JavaScript?
Let's imagine the case where we have a function that validates a username. A master function simply utilises 2 other functions that perform different checks.
Please note, all functions names are just examples.
// Returns a boolean
function validateUsername (username) {
return validateUsernameFormat(username) &&
isUsernameReserved(username);
}
// Returns a boolean
function validateUsernameFormat (username) {
return typeOf(username) === 'string' &&
username.match(/^\[a-z0-9]{8,20}$/);
}
// Returns a boolean
function isUsernameNotReserved (username) {
return ['igor', 'kristina'].indexOf(username) === -1;
}
Now let's imagine we augment our validation in the future by calling API to check if a given username already exists in our database.
// Now returns a promise
function isUsernameNotReserved (username) {
return API.checkIfUserNameAlreadyExists(username);
}
This would mean we will also now have to change the master validateUsername function since it now also needs to return promise. This would also probably mean we will have to modify all functions that use validateUsername function.
But what If we had all function in promises from scratch?
Option A - All functions return promises
// Returns a promise
function validateUsername (username) {
return validateUsernameFormat(username)
.then(() => {
return isUsernameReserved(username);
});
}
// Returns a promise
function validateUsernameFormat (username) {
return (
typeOf(username) === 'string' && username.match(/^\[a-z0-9]{8,20}$/) ?
Promise.resolve() : Promise.reject()
);
}
// Returns a promise
function isUsernameNotReserved (username) {
return (
['igor', 'kristina'].indexOf(username) === -1 ?
Promise.resolve() : Promise.reject()
);
}
Now if we want to augment isUsernameNotReserved with asynchronous API call, we don't need to change anything else.
Option B - Only functions calling another functions return promises
Also, another option would be write functions in promises that call another functions. In that case, only validateUsername should be written as a promise from scratch.
Is this a good approach? What could be the drawbacks apart from performance?
Upd: ran a simple performance test and though running consequent promises is slower, it practically should not make any difference since running 100000 consequent functions takes ~200ms, while running 1000 takes ~3ms in Chrome. Fiddle here https://jsfiddle.net/igorpavlov/o7nb71np/2/
Should I always return promises in all functions in JavaScript?
No.
If you have a function that performs an asynchronous operation or may perform an asynchronous operation, then it is reasonable and generally good design to return a promise from that function.
But, if your function is entirely synchronous and no reasonable amount of forethought thinks this will sometime soon contain an asynchronous operation, then there are a bunch of reason why you should not return a promise from it:
Asynchronous code writing and testing is more complicated than synchronous code writing and testing. So, you really don't want to make code harder to write and test than it needs to be. If your code can be synchronous (and just return a normal value), then you should do so.
Every .then() handler gets called on the next tick (guaranteed asynchronously) so if you take a whole series of synchronous operations and force each function to wait until the next tick of the event loop, you're slowing down code execution. In addition, you're adding to the work of the garbage collector for every single function call (since there's now a promise object associated with every single function call).
Losing the ability to return a normal value from a synchronous function is a huge step backwards in the language tools that you can conveniently use to write normal code. You really don't want to give that up on every single function.
Now if we want to augment isUsernameNotReserved with asynchronous API call, we don't need to change anything else.
A good API design would anticipate whether an asynchronous API is relevant or likely useful in the near future and make the API async only in that case. Because asynchronous APIs are more work to write, use and test, you don't want to unnecessarily just make everything async "just in case". But, it would be wise to anticipate if you are likely to want to use an async operation in your API in the future or not. You just don't want to go overboard here. Remember, APIs can be added to or extended in the future to support new async things that come along so you don't have to over complicate things in an effort to pre-anticipate everything that ever might happen in the future. You want to draw a balance.
"Balance" seems like the right word here. You want to balance the likely future needs of your API with developer simplicity. Making everything return a promise does not draw a proper balance, as it chooses infinite flexibility in the future while over complicating things that don't need to be as complicated.
In looking at a couple of your particular examples:
validateUsernameFormat() does not seem likely to ever need to be asynchronous so I see no reason for it to return a promise.
isUsernameNotReserved() does seem like it may need to be asynchronous at some point since you may need to look some data up in a database in order to determine if the user name is available.
Though, I might point out that checking if a user name is available before trying to just create it can create a race condition. This type of check may still be used as UI feedback, but when actually creating the name, you generally need to create it in an atomic way such that two requests looking for the same name can't collide. Usually this is done by creating the name in the database with settings that will cause it to succeed if the name does not already exist, but fail if it does. Then, the burden is on the database (where it belongs) to handle concurrency issues for two requests both trying to create the same user name.

How do promise chains start and finish

I'm a little confused about how the sequencing works in various documents I've come across. For instance, I have seen this sort of thing
let p = Promise.resolve();
for (let x in something)
{
/* do some hairy time consuming code */
p = p.then(dosomething(x));
}
return p.then(finalthing()).catch(pretendnobadthing());
What I really don't understand is that if you do something that takes a large amount of time in the main code, wouldn't that mean that one of the promises could complete before the main code actually got round to to setting up the .then.
Can you always use .then/.catch on a promise, and if its already reached completion, it'll carry on from the point it got to, so it conceptually looks like a big chain that will run to completion at some indeterminate point? And if so, doesn't that mean every time you create a promise chain it'll hang about for ever?
Can you always use .then/.catch on a promise, and if its already reached completion, it'll carry on from the point it got to, so it conceptually looks like a big chain that will run to completion at some indeterminate point?
Yes, you can always use .then/.catch on a promise. When you call p.then(), there are three possibilities.
The promise p is still pending (not fulfilled or rejected yet). If that's the case, then the function reference(s) you passed to .then() are registered as listeners for that promise. So, when a future state transition happens on the promise (either going from pending => fulfilled or from pending => rejected), then the appropriate registered listeners will be called.
The promise p is already fulfilled. If that's the case, then calling .then(f1, f2) will schedule f1 to be called on the next tick (after the current piece of Javascript finishes executing) and it will be passed the saved resolved value.
The promise p is already rejected. If that's the case, then calling .then(f1, f2) will schedule f2 to be called on the next tick (after the current piece of Javascript finishes executing) and it will be passed the saved reject reason.
So, it's perfectly safe to call .then() on a promise that is already fulfilled or rejected. The appropriate listener will just be scheduled to run on the next tick.
The same logic applies to .catch() except it is only interested in cases 1 and 3 above.
Here are
And if so, doesn't that mean every time you create a promise chain it'll hang about for ever?
Promises are just objects like any other objects in Javascript. They will hang around only while other code still has some live reference to them. As soon as there is no longer any way to reach that promise object, they will be eligible for garbage collection just like any other objects in Javascript.
So, if you do:
var p = somePromiseReturningFunction();
p.then(f1).then(f2).then(f3);
Then, p will remain around until somePromiseReturningFunction() is done with any references to the promise that it returned (usually, though not always, this occurs when the promise is finally fulfilled or rejected) and when the variable p goes out of scope. If p never goes out of scope (like when it's global or in some other lasting scope), then it will remain forever (just like any other Javascript object).
There are some misconceptions in your question so let me attempt to square those up.
You're using the construct p = p.then(dosomething(x)); which is likely not correct. You need to pass .then() a function reference. So, unless you want doSomething(x) to execute immediately and it also returns another function that is what you want called as then .then() handler (which seems unlikely here), then this is not the right construct. You probably meant to have:
p = p.then(result => dosomething(x));
or in ES5 syntax:
p = p.then(function(result) {
return dosomething(x)
});
You show the same issue in this too:
return p.then(finalthing()).catch(pretendnobadthing());
which should probably be:
return p.then(finalthing).catch(pretendnobadthing);
Remember, when you use f(), that means to execute f immediately. When you just pass f, that passes a function reference which the underlying function/method you are passing it to can then call later at the time of its choosing which is what you want for .then() and .catch() handlers.
What I really don't understand is that if you do something that takes a large amount of time in the main code, wouldn't that mean that one of the promises could complete before the main code actually got round to to setting up the .then.
First off, my original explanation at the beginning of my answer should explain that calling .then() on an already resolved promise is perfectly fine so this isn't an issue at all. It will just schedule action on the next tick of the event loop.
But, that isn't even the case here because Javascript in the browser and node.js is single-threaded so while your long-running code is running, that promise (who's async action was previously started) can't yet get resolved. Though the underlying async operation may be done and an event may be sitting in the Javascript event queue that will trigger a callback that will resolve the promise, that event in the event queue won't get processed until the current piece of Javascript that is executing is done and returns control to the system.
What I really don't understand is that if you do something that takes a large amount of time in the main code, wouldn't that mean that one of the promises could complete before the main code actually got round to to setting up the .then.
Since common implementations of JavaScript never run it in parallel, no. Nevertheless,
Can you always use .then/.catch on a promise, and if its already reached completion, it'll carry on from the point it got to, so it conceptually looks like a big chain that will run to completion at some indeterminate point?
yes! This is a big advantage of promises. Take this for example:
var promise = Promise.resolve(5); // already resolved here
setTimeout(function () {
promise.then(function (x) {
console.log(x); // still logs 5
});
}, 1000);
And if so, doesn't that mean every time you create a promise chain it'll hang about for ever?
Until it’s resolved, yes, but if the promise has already been resolved and there are no ways to reference it anymore, it can be disposed of like any other object.

Multiple producers for a single resolver/promise

In the Q documentation there is this line:
"You can give the resolver to any number of producers and whoever resolves the promise first wins. Furthermore, none of the producers can observe that they lost unless you give them the promise part too."
I don't really get what that is saying. Is this for when you are constructing a promise by hand? Can someone give me an example please?
Is this for when you are constructing a promise by hand?
Exactly, you can create a promise with a deferred or the promise constructor, call resolve multiple times but only the first time is effectful. For example:
var p = new Q.Promise(function(resolve){
resolve(1);
resolve(2);
resolve(3);
resolve(4);
resolve(5); // can also pass `resolve` around.
});
p.then(function(result){
// always 1, all other calls had no effect.
});
This lets you build interesting things, for example let's build a race function that returns the result of the first to resolve of two promises (error handling omitted for brevity):
function race(p1, p2){
return new Promise(function(resolve){
p1.then(resolve);
p2.then(resolve);
});
}
Which would resolve with whichever promise is ready first, for example:
race(tryToGetFromFirstAPI(), tryToGetFromSecondAPI()).then(function(result){
// resolves as soon as the "fastest" resolved, with the result
});
Yes, I recently raised an eyebrow at that statement. Unfortunately you need already to understand Deferreds/Promises in order to understand what is actually meant.
For me, the problem starts with the introductory sentence :
Deferreds are cool because they separate the promise part from the resolver part. So:
This is misleading because Deferreds don't actually separate these components - it's more accurate to say that they combine them, but allow their separation if required.
Off the cuff, better wording would be :
Deferreds [are cool because they] include the means to derive a Promise and include, in the form of executable methods, the means to resolve or reject, all wrapped up in a single object. So:"
The sentence starting "You can give the promise to any number of consumers ..." is a bit wordy but otherwise fine.
But the sentence starting "You can give the resolver to any number of producers ..." would better read :
The resolve and/or reject methods are readily detachable allowing you, for example, to pass them to any number of producers and whoever resolves/rejects first wins; furthermore, by passing the detached methods and not the Deferred itself (and hence its Promise), none of the producers can observe whether they won or lost."
A third statement might also be included :
A Deferred can be passed in its entirety, complete with its means to resolve/reject and to derive a Promise."
In fact, all of the above can, with a little jiggery-pokery, also be achieved with the new Promise(synchronousSettlerFunction) construction and outer var(s).
It should also be said that statements like this can be reviewed and improved many times over. My attempts above took me 15 minutes so I wouldn't pretend they are the last word.

Categories