Given that the client programmer both defines and uses the resolve function passed to the executor of a Promise, I naively assumed that I fully control the signature of the resolve function and so I can define it to take more than one arguments.
Yet the following code (jsFiddle) fails:
<html>
<script>
const promise = new Promise(function executor(resolve, reject) {
setTimeout(function () {
resolve(42, true);
}, 1000);
});
promise.then(function resolveCallback(answer, howCertain) {
console.log('callback called with arguments: ('+answer+', '+howCertain+')');
console.log('the answer is: '+answer+'. I am '+(howCertain?'very':'not very')+' certain about that');
});
</script>
</html>
The above code actually prints on the console:
callback called with arguments: (42, undefined)
the answer is: 42. I am not very certain about that
Digging a little deeper, I wrote the below code (jsFiddle):
<html>
<script>
const promise = new Promise(function executor(resolve, reject) {
console.log('entering executor, resolve is: ['+resolve+']'.);
setTimeout(function () {
console.log('about to call resolve');
resolve(42);
console.log('returning from resolve');
}, 1000);
});
console.log('about to call "then"');
promise.then(function resolveCallback(answer) {
console.log('the answer is: '+answer);
});
</script>
</html>
which actually prints the following on the console:
entering executor, resolve is: [function t() { [native code] }]
about to call "then"
about to call resolve
returning from resolve
the answer is: 42
This demonstrates a number of interesting things:
the executor is called before the client programmer has a chance to call then on the promise. And yet, the resolve parameter in the executor function is not undefined.
the resolveCallback function that is passed as argument in the call to then is not the same as the resolve function passed to the executor. Moreover, it is not executed synchronously (i.e. not in the same event loop run) with the resolve call from within the executor function.
The only way for Javascript to pull this off (that I can think of) is that the implementation is actually plugging some sort of "proxy" resolve and reject functions which are asynchronously linked to the actual resolve and reject functions supplied by the client programmer. This would also explain why you can't define your own signature for the resolve and reject functions: because the plumbing won't work.
Is this mental model correct or am I missing something?
The client programmer defines the resolve function passed to the executor of a Promise
No, he doesn't (as your experiment confirms). The executor is called during the new Promise creation.
When I call then on the promise, don't I pass a resolve function of my choosing?
No, you pass an onResolve listener callback, or actually an onFulfill callback.
Is my new mental model correct?
Yes, there is more plumbing below the surface.
Indeed, the new Promise constructor is giving you just proxy resolver functions.
A promise contains a state machine. It is an object representing an (one!) asynchronous result. As such, you can call .then() as many times on the same promise object, and the callbacks will always get passed the result.
It is not a wrapper around the executor function, it does not call the executor as often as you call then. The executor is called just once, to give the producer access to the resolver functions (the input of the state machine). The consumers that call then, watching the output of the state machine, are completely decoupled from this - as you say, they are asynchronously linked.
Also have a look at this. For your mental model, this is an easy-to-understand implementation of the Promise class (sans guaranteed asynchrony and error handling).
Related
I'm new to TypeScript and I have an async function like the one below. Can someone explain what it does and where resolve comes from? I hope I'm providing enough information for this.
async function SendMessage<T extends WorkerResponse>(msg: { id: number }): Promise<T>
{
const response = await new Promise<WorkerResponse>(resolve =>
{
waitingMessages.set(msg.id, resolve);
worker.postMessage(msg);
});
return response as T;
}
When I hover the mouse over the variables I get these:
(parameter) resolve: (value: WorkerResponse | PromiseLike<WorkerResponse>) => void
const waitingMessages: Map<number, (response: WorkerResponse) => void>
resolve comes from the Promise constructor. The Promise constructor calls the function you give it (the executor function) with two arguments. When defining an executor function, we idiomatically name the parameters to receive those arguments resolve and reject:
resolve - Resolves the promise (which may or may not fulfill it — here's my blog post on Promise terminology)
reject - Rejects the promise
The purpose of the code in the executor function is to start whatever asynchronous process the promise will report on, and then (when that process concludes), either: 1) use resolve to fulfill the promise, 2) use resolve to resolve the promise to another promise, or 3) use reject to reject the promise.
The async function you've shown does this:
Calls new Promise.
The Promise constructor calls the executor function passed to it synchronously, giving it access to resolve and reject functions. The one you've shown optimistically (and probably incorrectly) only uses a resolve parameter.
The executor code calls waitingMessages.set(msg.id, resolve);, which presumably sets up an eevn handler passing resolve as the handler implementation, and then worker.postMessage(msg); to send the message.
The code awaits the promise. (Which makes SendMessage return the promise it implicitly creates; it'll settle the promise it returns later.)
At some point, presumably the event gets fired and waitingMessages calls resolve, which probably fulfills the promise with some value (a fulfillment value).
Because the promise is fulfilled, the await is satisfied, and response gets assigned the fulfillment value of the promise that was awaited.
SendMessage's code returns that value, which fulfills the promise SendMessage implicitly returned, using the response value as the fulfillment value of that promise.
I've avoided going into too much detail above, but that's the gist.
None of this is specifically related to TypeScript, it's just how JavaScript promises work.
I suggest reading through Using Promises on MDN or any good Promise introductory tutorial or book.
As you can see he is building a new Promise object , which takes as parameter resolve and reject .
In this case as you can see it's returning the resolve function this is as saying Promise.resolve() with some values inside of it . But you are resolving and it's returning this object
{
waitingMessages.set(msg.id, resolve);
worker.`enter code here`postMessage(msg);
});
question is not really related to typescript but to javascript promise concept and async await .
What it does is that it creates a Promise, which provides you with a resolve function that you can run to mark the promise as fulfilled. If you await the SendMessage function, the code execution will stop until the resolve function is run.
It seems to add a message ID to some form of messages queue, and then send the message via a web worker. You can read more about web workers here
const result = await SendMessage(yourMessage);
console.log('These console.logs will not be run until something in your code..');
console.log('..executes the resolve function that was being stored via waitingMessages.set');
I have begun learning javascript promises. But I just can't understand the concept of promises.
The thing that bothers me most is who is passing the Resolver and Reject function to a promise constructor ?
See this example of Promise:
function getImage(url){
return new Promise(function(resolve, reject){
var img = new Image()
img.onload = function(){
resolve(url)
}
img.onerror = function(){
reject(url)
}
img.src = url
})
}
Now who does pass resolve and reject methods, as my understanding of javascript says to me that this script will throw unknown variable errors as resolve and rejects are not defined?
getImage('doggy.jpg').then(function(successurl){
document.getElementById('doggyplayground').innerHTML = '<img src="' + successurl + '" />'
}).catch(function(errorurl){
console.log('Error loading ' + errorurl)
})
Now you see a method like the above, the only way these methods(resolve and reject) are passed are via then and catch as used in above method call to getImage.
The thing that bothers me most is who is passing the Resolver and Reject function to a promise constructor ?
Nobody.
The functions are passed by the promise constructor.
They are passed to the function which you pass as the first argument to the promise constructor.
The Promise constructor is initialized with a callback, and the constructor passes reject and resolve as parameters when the callback is called.
Here is a simple demo:
class PromiseDemo {
constructor(cb) {
cb(this.resolve.bind(this), this.reject.bind(this));
}
resolve(d) {
console.log('resolve', d);
}
reject(d) {
console.log('reject', d);
}
}
new PromiseDemo((resolve, reject) => {
Math.random() > 0.5 ? resolve('1') : reject('1');
});
I had the same problem in understanding Promises.You need to look at the process of promise creation carefully.
when you write
var promise= new Promise(function(resolve,reject){...})
you are actually invoking constructor of Promise class or creating an object of Promise class. Now Promise constructor requires a function callback.
Now resolve and reject are just function arguments and not any other values.
You can write anything in place of resolve or reject like resolveHandler or rejectHandler.
These resolve or reject are nothing but the function callback that Promise calls when Promise is executed.
Now resolve is called when Promise is executed successfully and reject is called when promise is executed with some error or unsuccessfully .
The argument with which resolve is called can be accessed inside then like this
getImage().then(function(valueSentInResolve){ console.log('')})
The argument with which reject is called can be accessed inside catch like this
getImage().then(function(valueSentInResolve)
{//..do something}
).catch(function(errorSentInReject){
console.log('error',errorSentInReject )
})
I hope that helps.Let me know if I said anything wrong.
I have been studying Promises all day, and had the same question. I finally figured it out.
When you make a Promise object, you give the Promise Constructor an executor, which can be any function, as long as it has this signature.
anyFunction(resolutionFunction, rejectionFunction){
// typically, some asynchronous operation.
}
So any function with 2 functions as the arguments can be used. The first function is what you call when it works, the second is what you call when it breaks. You can name those functions whatever you want as well.
The Promise Constructor takes the function you pass in and does a few things with it.
It takes those 2 function arguments and generates a corresponding pair of functions that are "connected" to the Promise object.
It runs the executor
It ignores any return value from your executor
Now in your executor function when the promise resolves you call the positionally first function and pass it one value. It will look something like:
resolutionFunction(value)
You may be wondering, where is resolutionFunction defined? Remember the Promise Constructor defined that function for us. So we can call resolutionFunction without having to define it ourselves. Behind the scenes, when we call that resolutionFunction generated by the Promise Constructor, it sets the state of the promise to fulfilled, calls the function inside the promiseObject.then function, and passes the value into the .then function so you can use it.
You would call the 2nd positional function if the promise failed and the same things would happen and you could deal with the failure.
This Mozilla Doc on the Promise Constructor was very helpful.
Here is a short examples that shows what I explained above.
function anyFunction(callThisFunctionWhenItWorks, callThisFunctionWhenItBreaks) {
let importantNumber = 10; //change to 11 if you want the promise to reject
if (importantNumber == 10) {
callThisFunctionWhenItWorks('Hooray, success, so we call resolved for the promise.');
} else {
callThisFunctionWhenItBreaks('Boo, rejected because important number is not equal to 10');
}
}
//make a new promise
const examplePromise = new Promise(anyFunction);
//use the promise
examplePromise.then(function(result) {
console.log(result);
}).catch(function (error) {
console.log(error);
})
The promise library creates and passes those functions, along with all the other metadata needed to track the promise and record completion, store state and progress, cancel it, etc.
The folks behind Bluebird have published some info on how the library works internally, and you can see more in the Bluebird source.
does this make sense? This explanation could be completely incorrect!!
We provide the logic which should run asynchronously. The logic should accept 2 functions, resolve and reject. The reference of these functions is provided by Promise. These functions should be called by our logic when we have the final value or error. The Promise created initially is in Pending state. Calling resolve and reject changes the state to Fulfilled or Rejected respectively.
executeFunction(res,rej) = {
do some op, say DB query.
if (success) res(value) //executeFunction uses the resolving functions to change state of the Promise. Calling res fulfills the promise with value
if (fail) rej(reason)//executeFunction uses the resolving functions to change state of the Promise. Calling rej rejects the promise with reason
}
Rather than calling executeFunction directly (which would make the call synchronous), we create a Promise will will run the executeFunction code in a separate thread (asynchronously) let p = Promise(executeFunction(res,rej));. We get back a reference of the Promise.
My guess is that internally in the Promise, the following happens
Promise(e(res,rej)) = {
// the Promise's constructor creates a new promise, initially in the pending state. It calls `e` (the executeFunction function) and provides references to the resolving functions to it that can be used to change its state.
state = pending;
e(_res,_rej); //starts my op. asynchronously (a new thread). Reference to resolving functions, _res, _rej is provided. _res and _rej are Promise's internal functions (see below)
//constructor doesn't return till the async thread finishes
}
_res (value){ //Promise's internal method
//probably sets the state of promise to Fulfilled and store the result of the Promise
state = fulfilled
resolvedValue = value;
}
_rej {//Promise's internal method
probably sets the state of promise to Rejected and store the result of the Promise
state = rejected
resolvedValue = error;
}
Creating the Promise starts the execution of the code asynchronously. Now we are interested in knowing what is the result of executeFunction (we don't care when executeFunction finishes). To do this, we call then of the Promise p. then takes two optional arguments and registers them as callbacks. I am not sure when and who calls these callbacks. I know that then returns another Promise but I am not able to understand how that works
then(executeFnIfPromiseResolved, executeFnIfPromiseRejected):Promise {
register executeFnIfPromiseResolved as callback
register executeFnIfPromiseRejected as callback
//NOT SURE WHO AND WHEN THE CALLBACKS ARE CALLED
//then needs to return Promise. What would be the executor function of that Promise?
}
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.
The following javascript function is from You Don't Know JS: Async & Performance. According to my understanding, the first comment // start doing something that could take a while is misleading. The section of the code where something is actually done possibly asynchronously is in the function passed into the Promise constructor.
function foo(x) {
// start doing something that could take a while *misleading comment*
// construct and return a promise
return new Promise( /* executor */ function(resolve,reject){
// eventually, call `resolve(..)` or `reject(..)`,
// which are the resolution callbacks for
// the promise.
} );
}
I would fix it in the following way:
function foo(x) {
// construct and return a promise
return new Promise( /* executor */ function(resolve,reject){
// start doing something that could take a while
// then foo returns the newly created Promise
// eventually, call `resolve(..)` or `reject(..)`,
// which are the resolution callbacks for
// the promise.
} );
}
Yes, this should be fixed (thanks for filing this issue).
This reminds me a bit of the difference between the deferred pattern and the revealing constructor pattern. Starting the asynchronous task inside the promise constructor callback has two advantages:
If it throws synchronously (e.g. a syntax error, a typo in the method invocation etc), the exception will be caught implicitly and reject the promise
The resolve and reject callbacks are already in scope to be passed to the asynchronous process as callbacks.
The answer is: nowhere is code executed asynchronously in a promise. *
While the second form you show is slightly more advantageous, this is solely because it handles errors more consistently (expecting callers to handle both exceptions and rejections is poor form).
Addressing your main confusion: The promise executor function runs synchronously. From MDN:
The executor function is executed immediately by the Promise implementation, passing resolve and reject functions (the executor is called before the Promise constructor even returns the created object).
And the spec:
Returning from the executor function does not mean that the deferred action has been completed but only that the request to eventually perform the deferred action has been accepted.
It is up to you to launch any asynchronous operation that eventually calls resolve or reject:
new Promise(resolve => setTimeout(resolve, 2000))
.then(() => console.log("Async"));
console.log("Sync");
Most importantly, the Promise constructor only exists to wrap legacy functions that don't support promises already. Don't use it for anything else.
*) Actually, .then guarantees that functions passed to it never run immediately, so my first statement isn't entirely correct. The soonest they can run is at the end of the same run of the event loop, in a micro-task queue. Hardly what you're after.
I have begun learning javascript promises. But I just can't understand the concept of promises.
The thing that bothers me most is who is passing the Resolver and Reject function to a promise constructor ?
See this example of Promise:
function getImage(url){
return new Promise(function(resolve, reject){
var img = new Image()
img.onload = function(){
resolve(url)
}
img.onerror = function(){
reject(url)
}
img.src = url
})
}
Now who does pass resolve and reject methods, as my understanding of javascript says to me that this script will throw unknown variable errors as resolve and rejects are not defined?
getImage('doggy.jpg').then(function(successurl){
document.getElementById('doggyplayground').innerHTML = '<img src="' + successurl + '" />'
}).catch(function(errorurl){
console.log('Error loading ' + errorurl)
})
Now you see a method like the above, the only way these methods(resolve and reject) are passed are via then and catch as used in above method call to getImage.
The thing that bothers me most is who is passing the Resolver and Reject function to a promise constructor ?
Nobody.
The functions are passed by the promise constructor.
They are passed to the function which you pass as the first argument to the promise constructor.
The Promise constructor is initialized with a callback, and the constructor passes reject and resolve as parameters when the callback is called.
Here is a simple demo:
class PromiseDemo {
constructor(cb) {
cb(this.resolve.bind(this), this.reject.bind(this));
}
resolve(d) {
console.log('resolve', d);
}
reject(d) {
console.log('reject', d);
}
}
new PromiseDemo((resolve, reject) => {
Math.random() > 0.5 ? resolve('1') : reject('1');
});
I had the same problem in understanding Promises.You need to look at the process of promise creation carefully.
when you write
var promise= new Promise(function(resolve,reject){...})
you are actually invoking constructor of Promise class or creating an object of Promise class. Now Promise constructor requires a function callback.
Now resolve and reject are just function arguments and not any other values.
You can write anything in place of resolve or reject like resolveHandler or rejectHandler.
These resolve or reject are nothing but the function callback that Promise calls when Promise is executed.
Now resolve is called when Promise is executed successfully and reject is called when promise is executed with some error or unsuccessfully .
The argument with which resolve is called can be accessed inside then like this
getImage().then(function(valueSentInResolve){ console.log('')})
The argument with which reject is called can be accessed inside catch like this
getImage().then(function(valueSentInResolve)
{//..do something}
).catch(function(errorSentInReject){
console.log('error',errorSentInReject )
})
I hope that helps.Let me know if I said anything wrong.
I have been studying Promises all day, and had the same question. I finally figured it out.
When you make a Promise object, you give the Promise Constructor an executor, which can be any function, as long as it has this signature.
anyFunction(resolutionFunction, rejectionFunction){
// typically, some asynchronous operation.
}
So any function with 2 functions as the arguments can be used. The first function is what you call when it works, the second is what you call when it breaks. You can name those functions whatever you want as well.
The Promise Constructor takes the function you pass in and does a few things with it.
It takes those 2 function arguments and generates a corresponding pair of functions that are "connected" to the Promise object.
It runs the executor
It ignores any return value from your executor
Now in your executor function when the promise resolves you call the positionally first function and pass it one value. It will look something like:
resolutionFunction(value)
You may be wondering, where is resolutionFunction defined? Remember the Promise Constructor defined that function for us. So we can call resolutionFunction without having to define it ourselves. Behind the scenes, when we call that resolutionFunction generated by the Promise Constructor, it sets the state of the promise to fulfilled, calls the function inside the promiseObject.then function, and passes the value into the .then function so you can use it.
You would call the 2nd positional function if the promise failed and the same things would happen and you could deal with the failure.
This Mozilla Doc on the Promise Constructor was very helpful.
Here is a short examples that shows what I explained above.
function anyFunction(callThisFunctionWhenItWorks, callThisFunctionWhenItBreaks) {
let importantNumber = 10; //change to 11 if you want the promise to reject
if (importantNumber == 10) {
callThisFunctionWhenItWorks('Hooray, success, so we call resolved for the promise.');
} else {
callThisFunctionWhenItBreaks('Boo, rejected because important number is not equal to 10');
}
}
//make a new promise
const examplePromise = new Promise(anyFunction);
//use the promise
examplePromise.then(function(result) {
console.log(result);
}).catch(function (error) {
console.log(error);
})
The promise library creates and passes those functions, along with all the other metadata needed to track the promise and record completion, store state and progress, cancel it, etc.
The folks behind Bluebird have published some info on how the library works internally, and you can see more in the Bluebird source.
does this make sense? This explanation could be completely incorrect!!
We provide the logic which should run asynchronously. The logic should accept 2 functions, resolve and reject. The reference of these functions is provided by Promise. These functions should be called by our logic when we have the final value or error. The Promise created initially is in Pending state. Calling resolve and reject changes the state to Fulfilled or Rejected respectively.
executeFunction(res,rej) = {
do some op, say DB query.
if (success) res(value) //executeFunction uses the resolving functions to change state of the Promise. Calling res fulfills the promise with value
if (fail) rej(reason)//executeFunction uses the resolving functions to change state of the Promise. Calling rej rejects the promise with reason
}
Rather than calling executeFunction directly (which would make the call synchronous), we create a Promise will will run the executeFunction code in a separate thread (asynchronously) let p = Promise(executeFunction(res,rej));. We get back a reference of the Promise.
My guess is that internally in the Promise, the following happens
Promise(e(res,rej)) = {
// the Promise's constructor creates a new promise, initially in the pending state. It calls `e` (the executeFunction function) and provides references to the resolving functions to it that can be used to change its state.
state = pending;
e(_res,_rej); //starts my op. asynchronously (a new thread). Reference to resolving functions, _res, _rej is provided. _res and _rej are Promise's internal functions (see below)
//constructor doesn't return till the async thread finishes
}
_res (value){ //Promise's internal method
//probably sets the state of promise to Fulfilled and store the result of the Promise
state = fulfilled
resolvedValue = value;
}
_rej {//Promise's internal method
probably sets the state of promise to Rejected and store the result of the Promise
state = rejected
resolvedValue = error;
}
Creating the Promise starts the execution of the code asynchronously. Now we are interested in knowing what is the result of executeFunction (we don't care when executeFunction finishes). To do this, we call then of the Promise p. then takes two optional arguments and registers them as callbacks. I am not sure when and who calls these callbacks. I know that then returns another Promise but I am not able to understand how that works
then(executeFnIfPromiseResolved, executeFnIfPromiseRejected):Promise {
register executeFnIfPromiseResolved as callback
register executeFnIfPromiseRejected as callback
//NOT SURE WHO AND WHEN THE CALLBACKS ARE CALLED
//then needs to return Promise. What would be the executor function of that Promise?
}