Can someone help me understand why the following code prints blank? I'm expecting it to print "done" as I assume that the await will make the program wait for the promise to resolve.
Thanks for the help!
var y = '';
async function f() {
let promise = new Promise((resolve, reject) => {
setTimeout(() => resolve("done!"), 1000)
});
let result = await promise; // wait till the promise resolves (*)
y = result;
}
f().then(console.log(y));
You must pass a callback function to then, not call console.log immediately and pass its return value:
f().then(() => console.log(y));
Of course the code would be much better if you didn't use a global variable but rather returned the value from the async function so that the promise fulfilled with it:
async function f() {
const promise = new Promise((resolve, reject) => {
setTimeout(resolve, 1000)
});
await promise;
const result = "done!";
return result;
}
f().then((y) => console.log(y));
Related
I'm trying to get the value of an inputed variable on a callback function and assign it into another variable value outside this callback function.
I'm using async/await but not working (the assignment runs before the callback function), any suggestion?
async function iniciar() {
let my_prep = '';
await readline.question('Insert preposition', (prep) => {
**my_prep = prep;**
readline.close();
});
console.log('OK',my_prep);
return true;
}
Thanks for reading!
You can do something like this.
const question = () => {
return new Promise((resolve, reject) => {
readline.question('Insert preposition ', (prep) => {
readline.close();
resolve(prep)
})
})
}
async function iniciar() {
let my_prep = await question();
console.log('OK',my_prep);
return true;
}
await keyword waits on the promise to resolve, so you need to return promise. Also the use of async/await and promises is to avoid callback hell.
Consider the following promise array
const promiseArray = [1, 2, 3].map(num =>
new Promise(async resolve => {
while (num > 0) {
await foo();
num--;
}
await bar(num);
resolve(); // No value to return
})
);
const a = Promise.all(promiseArray);
Is the resolve function necessary?
Can we omit it and turn the promise into something like this?
const promiseArray = [1, 2, 3].map(num =>
new Promise(async () => {
while (num > 0) {
await foo();
num--;
}
await bar(num);
})
);
const a = Promise.all(promiseArray);
Yes, calling resolve or reject is necessary when using the new Promise constructor, otherwise the promise will stay pending.
However, in your case, you shouldn't be using new Promise at all:
const promiseArray = [1, 2, 3].map(async num => {
while (num > 0) {
await foo();
num--;
}
await bar(num);
});
const a = Promise.all(promiseArray);
Can we omit it and turn the promise into something like this?
No, you cannot. Without calling resolve(), your new Promise() will never resolve. When you then call:
const a = Promise.all(promiseArray);
None of the promises in promiseArray will ever resolve. So, the promise a will never resolve. So, none of this will be of any use and you will have no way of knowing when everything is done executing.
It doesn't appear you really need to wrap anything in a promise here. You can just do this:
async function runLoop() {
for (let i = 1; i <= 3; i++) {
let num = i;
while (num > 0) {
await foo();
num--;
}
await bar(num); // note this will always be bar(0)
}
}
runLoop().then(() => {
console.log("all done");
}).catch(err => {
console.log(err);
});
Or, if you want your separate loops to run in parallel, you can do this:
const promiseArray = [1, 2, 3].map(async num => {
while (num > 0) {
await foo();
num--;
}
await bar(num); // note this will always be bar(0)
});
Promise.all(promiseArray).then(() => {
console.log("all done");
}).catch(err => {
console.log(err);
});
When you create the promise using constructor, first parameter should be called to resolve the promise, the second parameter(if present) to the function should be called to reject the promise. If you are not calling any of the params then promise will be in the pending state always. More information
I think you are confused with async/await and promises.
When you specify async function it will always return resolved promise unless you throw an error inside function which is not caught.
For example:
async function hello(){ return 1}
hello().then((val) => console.log(val));
The same example you can implement using promises
let promise = return new Promise((resolve) => return resolve(1));
promise.then((val) => console.log(val));
How to change the value of data inside the asyncCall() and set it to the resolve value of the promise which is b.
What I wanted is that the asyncCall() will return b.
But what happen is that asyncCall() returns a Promise object.
function resolveAfter2Seconds(data) {
return new Promise(resolve => {
resolve(data);
});
}
async function asyncCall() {
let data = "a";
var result = await resolveAfter2Seconds("b");
data = result;
return data;
}
asyncCall();
Use IIFE
Making the function async will automatically have it return a Promise. You will either have to await it, or use .then to access the resolved value. IIFE stands for "Immediately Invoked Function Expression" – Tim VN
function resolveAfter2Seconds(data) {
return new Promise(resolve => {
resolve(data);
});
}
async function asyncCall() {
let data = "a";
var result = await resolveAfter2Seconds("b");
data = result;
return data;
}
(async function() {
console.log(await asyncCall())
})()
An async function will always return a Promise (see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function#Return_value).
If you put a console.log(result) statement in the asyncCall() function body, you will realize that the value is actually resolved right there and can be used as you'd expect it. But as documented, the return value of an async function will always be "promisified", so you'd have to "await" that function call too.
To do that at the top (global) level, you can either use an IIFE (Immediately Invoked Function Expression):
(async () => console.log(await asyncCall()))();
or fall back to classical callback functions using Promise.then():
asyncCall().then(value => console.log(value));
Some browsers also support top level await expressions:
await asyncCall();
declaring function with async will return classic Promise.
so you have to use callbacks or await.
async function asyncCall() will return Promise not the result you want to.
asyncCall().then((data) => console.log('in data is your result'));
Async functions return a promise itself:
function resolveAfter2Seconds(data) {
return new Promise(resolve => {
return resolve(data);
});
}
async function asyncCall() {
const result = await resolveAfter2Seconds("b");
return result;
}
asyncCall().then(
data => console.log(data)
);
In an attempt to understand promises more clearly, i have been reading up a few very interesting articles on the same. I came across the following code which works perfectly for executing promises sequentially. But i am not able to understand how it works.
function doFirstThing(){
return new Promise(function(resolve,reject){
setTimeout(()=>{
resolve(1);
},1000)
})
}
function doSecondThing(res){
return new Promise(function(resolve,reject){
setTimeout(()=>{
resolve(res + 1);
},1000)
})
}
function doThirdThing(res){
return new Promise(function(resolve,reject){
setTimeout(()=>{
resolve(res + 2);
},1000)
})
}
promiseFactories = [doFirstThing, doSecondThing, doThirdThing];
function executeSequentially(promiseFactories) {
var result = Promise.resolve(); // this is the most problematic line
promiseFactories.forEach(function (promiseFactory) {
result = result.then(promiseFactory);// what is happening here ?
});
return result;
}
executeSequentially(promiseFactories)
I do understand that promises are executed as soon as they are created. For some reason i am not able to understand the flow of execution. Especially this following line:
var result = Promise.resolve()//and empty promise is created.
Please if somebody can help me understand how calling the promiseFactory method inside the 'then' method of the empty promise makes it execute sequentially, like so. Or is it because of the forEach loop ?
result = result.then(promiseFactory);
I tried replacing the 'forEach' with a 'map' function and still yielded the same result. i.e, the methods where executed sequentially.
Also, how is the value passed from one chained function to other ?
Any help or article/blog is highly appreciated.
You can image a Promise as a box with execution inside. As far as the promise is created, the execution starts. To get the result value, you have to open the box. You can use then for it:
Promise.resolve(5).then(result => console.log(result)); // prints 5
If you want to chain promises you can do it by opening the box one by one:
Promise.resolve(5)
.then(result => Promise.resolve(result + 1))
.then(result => Promise.resolve(result * 2))
.then(result => console.log(result)); // prints 12
This chaining makes the executions synchronous (one by one).
If you want to execute several promises asynchronously (you don't chain results), you can use Promise.all:
Promise.all([Promise.resolve(1), Promise.resolve(2), Promise.resolve(3)])
.then(result => console.log(result)); // prints [1,2,3]
In your case:
Promise.all(promiseFactories).then(result => console.log(result));
Another option how to work with promises is to await them:
(async ()=> {
var res1 = await Promise.resolve(5);
var res2 = await Promise.resolve(res1 + 1);
var res3 = await Promise.resolve(res2 * 2);
console.log(res3); // prints 12
})();
await works similar to then - it makes asynchronous execution to synchronous.
In your case:
async function executeSequentially(promiseFactories) {
for (const p of promiseFactories) {
const result = await p;
console.log(result);
}
}
Note: await packs a value into a Promise out of the box:
var res1 = await 5; // same as await Promise.resolve(5)
The executeSequentially method returns all the Promises one after each other. It happens to iterate over promiseFactory, but it could be written as:
function executeSequentially(promiseFactories) {
return doFirstThing()
.then(() => doSecondThing())
.then(doThirdThing() );
}
It is just the same. We are basically returning a Promise.
Now, however, we want to iterate over a collection of promises.
When iterating, we need to attach the current Promise to the previous with a then. But the forEach does not expose the next Promise -or the previous- in every iteration. And yet we still need it in order to keep chaining Promises one by one. Hence, the result 'hack':
function executeSequentially(promiseFactories) {
var result = Promise.resolve(); /*We need a thing that keeps yelling
the previous promise in every iteration, so we can keep chaining.
This 'result' var is that thing. This is keeping a Promise in every
iteration that resolves when all the previous promises resolve
sequentially. Since we don't have a Promise in the array
previous to the first one, we fabricate one out of 'thin air'
with Promise.resolve() */
promiseFactories.forEach(function (promiseFactory) {
result = result.then(promiseFactory); /* Here result is update
with a new Promise, with is the result of chaining `result`
with the current one. Since `result` already had all the previous ones,
at the end, `result` will be a Promise that depends upon all the
Promises resolution.*/
});
return result;
}
Now, there's also a syntax quirk that maybe is puzzling you:
result = result.then(promiseFactory);
This line is pretty much the same as the following:
result = result.then(resolvedValue => promiseFactory(resolvedValue));
Please if somebody can help me understand how calling the promiseFactory method inside the 'then' method of the empty promise makes it execute sequentially, like so. Or is it because of the forEach loop ?
First thing first, promiseFactory is a pretty bad name there. The method should be better written as follows:
function executeSequentially(promises) {
var result = Promise.resolve(); // this is the most problematic line
promises.forEach(function (currentPromise) {
result = result.then(currentPromise);// what is happening here ?
});
return result;
}
So:
how calling the currentPromise method inside the 'then' method of the empty promise makes it execute sequentially?
It makes execute sequentially because when you attach a Promise to another by then, it executes sequentially. Is a then thing, it is not at all related to the fact that we are iterating over Promises. With plain Promises outside an iteration it works pretty much the same:
Promise.resolve() // fake Promises that resolves instanly
.then(fetchUsersFromDatabase) // a function that returns a Promise and takes
// like 1 second. It won't be called until the first one resolves
.then(processUsersData) // another function that takes input from the first, and
// do a lot of complex and asynchronous computations with data from the previous promise.
// it won't be called until `fetchUsersFromDatabase()` resolves, that's what
// `then()` does.
.then(sendDataToClient); // another function that will never be called until
// `processUsersData()` resolves
It is always recommended to use Promise.all if you want such behaviour:
function doFirstThing() {
return new Promise(function(resolve, reject) {
setTimeout(() => {
resolve(1);
}, 1000)
})
}
function doSecondThing(res) {
return new Promise(function(resolve, reject) {
setTimeout(() => {
resolve(res + 1);
}, 1000)
})
}
function doThirdThing(res) {
return new Promise(function(resolve, reject) {
setTimeout(() => {
resolve(res + 2);
}, 1000)
})
}
let promiseFactories = [doFirstThing(2), doSecondThing(1), doThirdThing(3)];
Promise.all(promiseFactories)
.then(data => {
console.log("completed all promises", data);
})
To run it sequentially one after another:
function doFirstThing() {
return new Promise(function(resolve, reject) {
setTimeout(() => {
resolve(1);
}, 1000)
})
}
function doSecondThing(res) {
return new Promise(function(resolve, reject) {
setTimeout(() => {
resolve(res + 1);
}, 3000)
})
}
function doThirdThing(res) {
return new Promise(function(resolve, reject) {
setTimeout(() => {
resolve(res + 2);
}, 5000)
})
}
promiseFactories = [doFirstThing, doSecondThing, doThirdThing];
function executeSequentially(promiseFactories) {
promiseFactories.forEach(function(promiseFactory) {
promiseFactory(1).then((data) => {
console.log(data)
});
});
}
executeSequentially(promiseFactories);
If we lay out the foreach loop it will look like the following
function doFirstThing(){
return new Promise(function(resolve,reject){
setTimeout(()=>{
console.log(1);
resolve(1);
},1000)
})
}
function doSecondThing(res){
return new Promise(function(resolve,reject){
setTimeout(()=>{
console.log(2);
resolve(res + 1);
},2000)
})
}
function doThirdThing(res){
return new Promise(function(resolve,reject){
setTimeout(()=>{
console.log(3);
resolve(res + 2);
},3000)
})
}
Promise.resolve()
.then(doFirstThing())
.then(doSecondThing())
.then(doThirdThing());
I do understand that promises are executed as soon as they are created. For some reason i am not able to understand the flow of execution. Especially this following line:
var result = Promise.resolve()//and empty promise is created.
This is just to get hold of the promise chain's starting point. Here it is an already resolved promise. To better understand it you can use one of your promises to get hold of the promise chain like below.
let promiseFactories= [doSecondThing, doThirdThing];
let result = doFirstThing();
promiseFactories.forEach(function (promiseFactory) {
result = result.then(promiseFactory);
});
This will also work.
I am calling a method a which is returning a promise and inside it I am calling a method which do some operation and update the count variable. I want all the promise get finish once the count is done but it is not stopping after reaching the value 10.
var count = 0;
function a(p){
return new Promise((resolve, reject) =>{
console.log(count);
if(count == 10) {console.log('sdfsdfsd'); resolve(Date.now()); }
callee().then(() => { count++; a(); } )
})
}
function callee(){ return new Promise((resolve) => resolve())}
a(1).then((res) => console.log(res)).catch((res) => console.log(res));
// So you have a function `foo` which returns a promise eventually resolved, you want to write a function
// `bar` that will call this function n times, waitinng between each call for the returned promise to be
// resolved. This function will itself return a promise
// this function returns a promise which is resolved after one second
const foo = () => new Promise(resolve => setTimeout(resolve, 1000));
// Recursively call the foo function until 0 is reached.
// This will actually create a chain of promises which settle after one second.
// It also uses the fact that if you return a promise `a` in the `then` handler the returned
// promise `b` will only settle when `a` is resolved.
const bar = n => {
if (n === 0) return Promise.resolve();
return foo().then(() => bar(n-1));
};
bar(10).then(() => console.log("done"));
var count = 0;
function a(p) {
return new Promise((resolve, reject) => {
console.log(count);
if (count == 10) { console.log('sdfsdfsd'); return resolve(Date.now()); }
return callee().then(() => {
count++;
return resolve(a());
})
})
}
function callee() { return new Promise((resolve) => resolve()) }
a(1).then((res) => console.log("res",res)).catch((res) => console.log(res))