I have been going in circles trying to deeply understand JS promises and I can't seem to find a simple answer on how in the world does it passes the value of the resolved to the handle success variable, I don't understand is that as a build method? But the name is (resolvedValue)
For example, I saw also in another example that they used (rejectionReason) to handle the rejected value, I want to understand how that happens.
here is the code:
const prom = new Promise((resolve, reject) => {
resolve('Yay!');
});
// this resolvedValue how does it happen?
const handleSuccess = (resolvedValue) => {
console.log(resolvedValue);
};
prom.then(handleSuccess); // Prints: 'Yay!'
First lets clarify on two different concepts:
Function Definition:
const exampleFunction=(name)=>{console.log(name)} // just defined, does nothing
Function Invocation:
exampleFunction("Erfan") // logs "Erfan"
In JavaScript, function definitions can be passed to another function ("a higher order function") as a parameter, usually we describe such situation as "the function taking a callback".
The higher order function then calls the callback according to its own implementation, and may or may not pass a value to it.
In your example, method then of the the prom is the higher order function. it takes a callback, passes the resolve value to it, and calls it. it doesn't care about its name, just looks for a function definition and calls it.
Credits to got to #Nirjal Paudel reference link, the answer to my question is :
it happens by paassing it in the value as an anonymous function.
Promises have a method called then that will run after a promise reaches resolve in the code. then will return the promise’s value as a parameter.
This is how you would return and log the value of the example promise:
const handleSuccess = (resolvedValue) => {
console.log(resolvedValue);
};
prom.then(handleSuccess);
The promise you created had a [[PromiseValue]] of 'Yay!'. This value is what will be passed into the anonymous function as a response
so this means that the name won't matter
Related
I am receiving an array from a promise function:
function func() {
return new Promise((resolve, reject) => {
//...
return someData;
})
}
then I can see the promise value using async/await:
async function getArrayContent() {
const a = await func();
console.log(a);
}
this does display the correct content however, I am looking to access the array and its contents in so it can be used outside the async getArrayContent() function. please note that I can't change func() as the promise is necessary to return data I am retrieving. Also, return a does not work because whenever I am logging the getArrayContent() which returns a it just shows another pending promise. However, in this promise it does show that the state is fulfilled and it does have the necessary value but I still cannot access that value outside the functions. I tried adding a variable outside getArrayContent() but variable remains undefined.
I am using this in Reactjs and some of the solutions I tried both did not work and/or caused an infinite loop.
Other posts on stackoverflow did not help either because they only shows how to log value inside a promise with .then() which I cannot use.
I need to be able to display the area in React with the map function
There is no way to do precisely what you are asking here.
As #pilchard succinctly said:
Once in async land, always in async land.
However, one thing you could do is, await the function and pass it as a prop to a child component (and only show the child component when the data is ready), Now you can use the value synchronously in the child component.
I have two ways to run a series of initialisations (that need to happen in a particular order).
Method 1:
dispatch('initialize1')
.then(dispatch('initialize2'))
.then(dispatch('initialize3'))
.then(dispatch('initialize4'))
.catch((error) => Log(error.message))
Method 2:
dispatch('initialize1')
.then(() => dispatch('initialize2'))
.then(() => dispatch('initialize3'))
.then(() => dispatch('initialize4'))
.catch((error) => Log(error.message))
Method 2 works perfectly, but Method 1 seems to not wait for each to finish before it moves onto the next one.
But this really confuses me because I thought that if I chained promises with thens (no callback function), it would wait for each to complete (synchronously); but if I put each promise in a callback then as soon as it received the promise it'd move onto the next - but it's the opposite??
Can anyone explain this to me?
I don't think it's relevant, but the dispatch comes from Vue's Vuex Store.
In method 1, you passed the result of calling the function dispatch instead of passing a function to the Promise chain, this will cause the dispatch functions be called first before the Promise chain actually starts executing, i.e. the dispatch functions has already been called when you initialize the chain.
You can check it out directly by running the following code right at your browser's console:
const dispatch = something => something
typeof dispatch('apple') === 'string' // true
typeof (() => { dispatch('apple') }) === 'function' // true
In method 2, you are passing functions this time, so the functions will be called at the right time by Promise, instead of being run at start.
Because you need a wrapper function in the first case:
.then(function() {
dispatch('initialize2')
})
Here you do the same thing:
.then(() => dispatch('initialize2'))
() => ... is a wrapper function similat to function() {...}.
You should take a look at how promises are supposed to work. In short they are made of two pieces, a resolvealgorithm and a then method available on promise instances. Your first example cannot work because it does not follow the semantics ( signature ) of the then method.
They are as follow : let p a promise, f a JS value. Calling p.then(f) we have the following case :
if f is not a function it is ignored, and p.then(f) returns a new promise q eventually settled with the same state as p.
if f is a function then when p is settled with a value, calling p.then(f) will return a new promise q which will be settled with the value / error produced by f. This is the critical part and what makes promises interesting : the procedure you pass in to the then attr will only be called after a value / error has first been produced by the original promise, hence your issue with example 1.
There is ofc a little bit more than that to promises and their semantics : thentakes two arguments, one for each path : value / error. The namings may differ but usually you see code along the lines :
p.then(proceed, handle)
with
function proceed ( successfulValueFromSomewhere ) { // return new value or promise }
function handle ( anErrorFromSomewhere ) { // handle it by returning a value or a promise ( for retry cases ) }
I mentioned earlier a resolve algorithm, this part is critical to understand how values returned from such handlers are used from the point of view of promises to create new promise.
This procedure ensures that your second example work, it works more or less like that ( please take a look at the specs or the docs at MDN for an in depth review ). Its purpose is to transition a promise to one of two states : fulfilled with a value or rejected with an error.
Let v be a value, p an unsettled promise to be resolved with v.
if v has a then method then call it with the function function ( v2 ) { resolve(v2); } : which means that if the callback is called, rerun the procedure with the value provided (v2).
if v does not have a then method then fulfill with v
if at any point an error is thrown during the resolution then rejectwith the error.
This procedure is not really difficult and explains why promises compose nicely together : they will call each other's thenmethod upon resolution, which means that they will execute sequentially if each callback returns a promise.
There is a bit more than that to the specs of promises, I strongly advise anyone to take a look at the articles on MDN and this article about the motivations behind this new primitive added to the language and how it solves (some) problems.
If this answer is obscure please comment I'll try to be clearer :)
my below code work fine and i can create some data on database with that, but after that i need to get latest inserted id from that to use in other place of code, but this function which exported return promise object and i can't assign variable as function result, for example:
module.exports = {
createNewUser: function (model) {
return new Promise((resolve, reject) => {
return model.create(
{
username: 'John'
})
.then(function (result) {
return result.userUniqueId;
})
.then(value => resolve(value));
});
},
};
return Promise object and i can't assign variable with returned result as
return result.userUniqueId;
i want to get result and print or assign variable as the result with this code:
console.log( controller.createNewUser( models.users ) );
yes, using coroutines and yield you can actually suspend the exeuction of a method and return the co function back to the caller, and caller can resume the execution at his will by using the co function object with an argument passing to the fraction of the routine - but there is no way for the routine to pass back a half-baked data to the caller, nor it makes meaning in this context: in your code, until you generate the unique IDs of the user, there is nothing to return to the caller, and the unique ID generation is asynchronous, and does not end until all the callback is executed. In short, the coroutine use case does not apply here. Hope this clarifies.
Dissecting the promise semantics:
It is just a semantic beautification two or more asynchronous calls.
Returning from anywhere in the chain is neither valid, nor meaningful.
As #Bergi points out, returning from partially executed asynchronous calls breaks the promise chain. Precisely, the caller-callee relation bound through a return value does not make make a valid semantic when Promise is involved.
Way out #1: create and return promise'd transaction to the caller, and then manage the rest of the chain in the caller (ugly).
Way out #2: Visualize the promise as the semantic wrapper around the old asynchronous call chains, and handle the result processing in the leaf of the promise chain (recommended).
Bottom-line: Caller does not get any stake in a call, where the callee take part in an asynchronous call.
Hope this helps.
I have a promise that returns data and I want to save that in variables. Is this impossible in JavaScript because of the async nature and do I need to use onResolve as a callback?
Can I somehow use this (e.g. wrap it with async/await):
const { foo, bar } = Promise.then(result => result.data, errorHandler);
// rest of script
instead of this?
Promise.then(result => {
const { foo, bar } = result.data;
// rest of script
}, errorHandler);
Note: Bluebird library is used instead of native implementation, and I can't change from Promise to asnyc/await or Generators.
NO you can't get the data synchronously out of a promise like you suggest in your example. The data must be used within a callback function. Alternatively in functional programming style the promise data could be map()ed over.
If your are OK using async/await (you should it's awesome) then you can write code that looks synchronous yet retain the asynchronicity of a promise (see #loganfsmyth comments).
const { foo, bar } = await iAmAPromise.then(result => result.data);
Overall since you are already using ES6 I assume you are also using a transpiler. In which case you should definitely give async/await a try.
Just be sure to weight in the decision that as today they are not yet a ratified specification.
While you can get a value from an awaited Promise inside an async function (simply because it pauses the function to await a result), you can't ever get a value directly "out" of a Promise and back into the same scope as the code that created the Promise itself.
That's because "out of" would mean trying to take something that exists in the future (the eventually resolved value) and putting it into a context (synchronous variable assignment) that already happened in the past.
That is, time-travel. And even if time-travel were possible, it probably wouldn't be a good coding practice because time travel can be very confusing.:)
In general, if you find yourself feeling like you need to do this, it's good sign that you need to refactor something. Note that what you're doing with "result => result.data" here:
Promise.then(result => result.data, errorHandler);
// rest of script
..is already a case of you working with (literally, mapping over) the value by passing it to a function. But, assuming that "// rest of script" does something important related to this value, you probably want to continue mapping over the now updated value with yet another function that then does something side-effect-y with the value (like display the data on the screen).
Promise
.then(({ data }) => data)
.then(data => doSomethingWithData(data))// rest of script
.catch(errorHandler);
"doSomethingWithData" will be called (if it's ever called) at some unknown point in the future. Which is why it's a good practice to clearly encapsulate all that behavior into a specific function and then hook that function up to the Promise chain.
It's honestly better this way, because it requires you to clearly declare a particular sequence of events that will happen, explicitly separated out from the first run through all of your application code's execution.
To put it another way, imagine this scenario, hypothetically executed in the global, top-level scope:
const { foo, bar } = Promise.then(result => result.data, errorHandler);
console.log(foo);
//...more program
What would you expect to happen there? There are two possibilities, and both of them are bad.
Your entire program would have to halt and wait for the Promise to execute
before it could know what "foo" & "bar" would... nay, might be. (this is
what "await," inside an async function, does in fact do: it pauses
the entire function execution until the value is available or an the error is thrown)
foo and bar would just be undefined (this is what actually
happens), since, as executed synchronously, they'd just be
non-existent properties of the top-level Promise object (which is not itself a "value,"
but rather a quasi-Monadic wrapper around getting an eventual value OR an error) which most
likely doesn't even contain a value yet.
let out; mypromise.then(x => out = x); console.log(out)
Only use this code when
you are debugging by hand,
and you know the promise has already succeeded
Behaviour of this code:
While the promise has not resolved yet, out will be undefined.
Once the promise resolves to a failure, an error is thrown.
When the promise resolves to success, (which may be after the console.log), the value of out will change from undefined to the Promise result — maybe in the middle of what you were doing.
In production code, or really any code that runs without you, the code that uses the Promise result should be inside the .then() callback, and not use some out variable. That way:
your code won't be run too early (when the result is still undefined),
and won't run too late (because you don't need 'I think sleeping for 10 seconds should do it' workarounds),
and won't erroneously run when the promise fails.
I have a solution of getting this value "out" if you will. This is a method at backend for uploading multiple files to AWS S3 which must be dealt asynchronously. I also need the responses from S3, so I need the values out of the Promise:
async function uploadMultipleFiles(files) {
const promises = []; //Creating an array to store promises
for (i = 0; i < files.length; i++) {
const fileStream = fs.createReadStream(files[i].path)
const uploadParams = {
Bucket: bucketName,
Body: fileStream,
Key: files[i].filename
}
promises.push(s3.upload(uploadParams).promise()) //pushing each promise instead
//of awaiting, to enable for concurrent uploads.
}
await Promise.all(promises).then(values => {
console.log("values: ", values) //just checking values
result = values; //storing in a different variable
});
return result; //returning that variable
}
The key lines in context with the issue being discussed here are these :
await Promise.all(promises).then(values => {
console.log("values: ", values) //just checking values
res = values; //storing in a different variable
});
return res; //returning that variable
But of course we have to also await in the function that will be calling this :
const result = await uploadMultipleFiles(files);
All you need to do is to extract all you have in your promise by using a .then
yourFunction().then( resp => {
... do what you require here
let var1 = resp.var1;
let var2 = resp.var2;
...
.....
})
yourFunction() should return a Promise
How to Get A Value From A Promise
YES! You can extract value out of a promise!
Do NOT let anyone here say you cannot. Just realize any variable that stores your returned promise value will likely have a short delay. So if you have a JavaScript script page that needs that data outside of the Promise or async-await functions, you may have to create loops, interval timers, or event listeners to wait to grab the value after some time. Because most async-await-promises are REST calls and very fast, that wait would require just a quick while loop!
It is easy! Just set a variable (or create a function) that can access the value inside your async or promise code and store the value in an outside variable, object, array, etc you can check on. Here is a primitive example:
// I just created a simple global variable to store my promise message.
var myDelayedData = '';
// This function is only used to go get data.
// Note I set the delay for 5 seconds below so you can test the delay
const getData = () => {
return new Promise((resolve, reject) => {
setTimeout(() => resolve('my promise data'), 5000);
});
}
// I like to create a second async function to get the data
// from the promise object and save the data to my global variable.
const processData = async () => {
let data = await getData();
// Save the delayed data to my global variable
myDelayedData = data;
}
// Start the data call from the promise.
processData();
// Open up your browser, hit F12 to pull up the browser devtools
// Click the "console" tab and watch the script print out
// the value of the variable with empty message until after
// 5 seconds the variable is assigned to the resolved promise
// and apears in the message!
// THAT IS IT! Your variable is assigned the promise value
// after the delay I set above!
// TEST: But let's test it and see...
var end = setInterval(function(){
console.log("My Result: " + myDelayedData);
if(myDelayedData !== ''){
clearInterval(end);
}
}, 1000);
// You should see this in devtools console.
// Each line below represents a 1 second delay.
My Result:
My Result:
My Result:
My Result: my promise data
Most people seeing this code will say "Then why use a Promise, just make a call for the data, pause, and update your application?" True: The whole point of a Promise is to encapsulate data processes inside the promise and take actions while the rest of the script continues.
But... you may need to output a result outside the Promise. You may have other global processes that need that data because it changes the state of the global application, for example. But at least you know you can get to that Promise data if you needed it.
I have the following code:
function doSomething() {
//xhr here
setTimeout(function() {
var value = 42;
}, 10);
return {
then: function(callback) {
callback(value);
}
};
}
doSomething().then(function(result) {
log("got a result", result);
});
And can't figure out how to access the value.
I need this to be promise-based solution in order to use in multiple places
JSFidle link
Update:
We are not using any libraries in that projects
There are a couple of problems there:
value is local to the function you're passing into setTimeout, because that's where you've declared it. You could fix this issue by declaring it in doSomething instead.
The bigger issue is that what you have there isn't a promise, it's just a function that returns an object when you call it that has a then method. Here's the order in which things happen:
You call doSomething
It sets a timer to set a value.
It creates an object with a then function.
It returns the object.
You call the then function immediately.
then tries to access value (which it can't because of the declaration issue, but would be a problem anyway).
Some time later, value is set by the callback when the timer fires.
To be a promise, the then function on object you return would have to store a reference to the callback passed into it, and call the callback later, when value has been set (e.g., the promise has been fulfilled).
Rather than implementing your own promises library, I'd suggest using one of the several that have already been written and debugged.
I'm just pointing out, that in order to "fix" your issue you need to return the then this way:
function doSomething() {
//xhr here
return {
then: function(callback) {
setTimeout(function() {
callback(42); // callback from within the async action
}, 10);
}
};
}
doSomething().then(function(result) {
log("got a result", result);
});
Please read TJ's answer and consider using a promise library - also consider reading this post that explains how promise resolution looks like.
Namely: Your then needs to in turn return a promise when called (rather than just set a timeout) for chaining, and the callback should be assimilated before waiting for it.