I am attempting a basic concept that is still eluding me...
In the option (that is commented out) including the Start().then... I'm able to nest the functions so that they start and end in the desired order.
In the await version, they start & end in the appropriate order but I'm not clear how I'm meant to put in log the resolve text after each one has completed. Sorry this is basic...
console.log("Synchronous result.");
function Start() {
return new Promise(function (resolve) {
console.log(`Starting the Start`);
setTimeout(() => resolve("Start has finished"), 5000);
});
}
function Middle() {
return new Promise(function (resolve) {
console.log(`Starting the Middle`);
setTimeout(() => resolve("Middle has finished"), 2000);
});
}
function End() {
return new Promise(function (resolve) {
console.log(`Starting the End`);
setTimeout(() => resolve("End has finished"), 1000);
});
}
// this works in the traditional promise method
/*
Start().then((result) => {
console.log(result),
Middle().then((result) => {
console.log(result),
End().then((result) => {
console.log(result);
});
});
});
*/
// now trying async/await
async function workflow() {
let call1 = await Start();
let call2 = await Middle();
let call3 = await End();
}
workflow();
Well, you almost have it. In an async function, the await will return the result of the promise. So all you have to do is do the console.log after.
console.log("Synchronous result.");
function Start() {
return new Promise(function (resolve) {
console.log(`Starting the Start`);
setTimeout(() => resolve("Start has finished"), 5000);
});
}
function Middle() {
return new Promise(function (resolve) {
console.log(`Starting the Middle`);
setTimeout(() => resolve("Middle has finished"), 2000);
});
}
function End() {
return new Promise(function (resolve) {
console.log(`Starting the End`);
setTimeout(() => resolve("End has finished"), 1000);
});
}
// this works in the traditional promise method
/*
Start().then((result) => {
console.log(result),
Middle().then((result) => {
console.log(result),
End().then((result) => {
console.log(result);
});
});
});
*/
// now trying async/await
async function workflow() {
let call1 = await Start();
console.log(call1);
let call2 = await Middle();
console.log(call2);
let call3 = await End();
console.log(call3);
}
workflow();
The resolve method of the new Promise you can imagine as a returnvalue. In this case you returning strings, what gets assigned to the variables call1 call2 call3. You can resolve any valid javascript data structure.
// now trying async/await
async function workflow() {
let call1 = await Start();
console.log("call1: ", call1);
let call2 = await Middle();
console.log("call2: ", call2);
let call3 = await End();
console.log("call3: ", call3);
}
workflow();
As you get a bit more hands on, you can also discover the Promise.all() and Promise.allSettled().
The async/await is the moder way of Promiseusage. Keep it like this.
await XXX evaluates to be the resolved value of the promise XXX.
So the variables you've named callX contain the resolved values.
console.log("Synchronous result.");
function Start() {
return new Promise(function (resolve) {
console.log(`Starting the Start`);
setTimeout(() => resolve("Start has finished"), 5000);
});
}
function Middle() {
return new Promise(function (resolve) {
console.log(`Starting the Middle`);
setTimeout(() => resolve("Middle has finished"), 2000);
});
}
function End() {
return new Promise(function (resolve) {
console.log(`Starting the End`);
setTimeout(() => resolve("End has finished"), 1000);
});
}
// this works in the traditional promise method
// now trying async/await
async function workflow() {
let call1 = await Start();
console.log({call1});
let call2 = await Middle();
console.log({call2});
let call3 = await End();
console.log({call3});
}
workflow();
Related
This question already has answers here:
Why does the `then()` handler of a promise execute immediately?
(3 answers)
Closed last month.
I apologize if this is a basic question. I am really puzzled by how Promise works in Javascript.
I have the following piece of code:
function wait(ms) {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log("Done waiting");
resolve(ms);
}, ms);
});
}
let a = true;
let p = new Promise(async (resolve, reject) => {
await wait(3000);
console.log("Inside Promise");
if (a) {
resolve("Success");
} else {
reject("Failure");
}
});
const func = async () => {
let output = await p;
console.log(output);
};
func().then(console.log("abc"));
This is the printout:
abc
Done waiting
Inside Promise
Success
I cannot, for the life of me, figure out why abc is printed first. Shouldn't it wait for func() to finish executing? I expected abc to be printed last. Can anyone walk me through the steps of execution? Thanks in advance. I would really appreciate it.
What you've provided to Promise.then is not a callback and it is evaluated immediately at runtime. You need to move the console.log into the body of the function instead:
func().then(() => console.log("abc"));
See working example below:
function wait(ms) {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log("Done waiting");
resolve(ms);
}, ms);
});
}
let a = true;
let p = new Promise(async (resolve, reject) => {
await wait(3000);
console.log("Inside Promise");
if (a) {
resolve("Success");
} else {
reject("Failure");
}
});
const func = async () => {
let output = await p;
console.log(output);
};
func().then(() => console.log("abc"));
Trying to learn proper async/await JavaScript to run functions in sequence when an early function in the sequence would be delayed (using setTimeout to simulate). I'm not getting the expected results (still getting "first", "second", "this should run first?" - see code).
What am I missing? Do I have the wrong idea about this?
Thanks in advance!
const zeroFunction = () => {
setTimeout(() => {
return new Promise((resolve) => {
console.log("This should run first?");
resolve();
});
}, 2000)}
const firstFunction = () => {
return new Promise((resolve) => {
console.log("first");
resolve();
})
}
const secondFunction = () => {
return new Promise((resolve) => {
console.log("second");
resolve();
})
}
async function fnAsync() {
await zeroFunction();
await firstFunction();
secondFunction();
}
fnAsync();
zeroFunction is currently returning undefined implicitly, not a Promise. Inverse the wrapping of the setTimeout and Promise constructor and it should work as expected.
const zeroFunction = () => {
return new Promise((resolve) => {
setTimeout(() => {
console.log("This should run first?")
resolve()
}, 2000)
})
}
const firstFunction = () => {
return new Promise((resolve) => {
console.log("first")
resolve()
})
}
const secondFunction = () => {
return new Promise((resolve) => {
console.log("second")
resolve()
})
}
async function fnAsync() {
await zeroFunction()
await firstFunction()
secondFunction()
}
fnAsync()
I have a function call like so:
await someFunction(foo);
With someFunction defined like:
const someFunction = foo => {
return new Promise((resolve, reject) => {
if (foo) {
return resolve(someOtherPromise());
}
reject();
}
}
Is this valid code? I have tested it and it seems ok.
Is it correct that await someFunction() will transform to await someOtherPromise() if foo is true i.e. will it continue waiting for someOtherPromise to resolve?
Yes, it is valid code and works by resolving with a promise, but smells like the Promise constructor antipattern. I would instead recommend to write
function someFunction(foo) {
if (foo)
return someOtherPromise();
else
return Promise.reject();
}
or
async function someFunction(foo) {
if (foo)
return someOtherPromise();
else
throw;
}
(and better throw a new Error with a message, not undefined)
I've written some test code to see if it's true:
const someFunction = foo => {
return new Promise((resolve, reject) => {
if (foo) {
return resolve(someOtherPromise(2000));
}
reject();
});
}
const someOtherPromise = async(ms) => {
return new Promise(resolve => setTimeout(() => {
console.log("i'm about to resolve in someOtherPromise");
resolve();
}, ms));
}
const run = async () => {
await someFunction('foo');
console.log('finished waiting for someFunction');
}
run();
I have written 3 function to test it out.
c = () => new Promise((resolve, reject) => {
setTimeout(() => {
console.log('c');
resolve();
}, 1000);
});
b = () => new Promise((resolve, reject) => {
setTimeout(() => {
console.log('b');
resolve(c());
}, 1000);
});
a = async () => {
console.log('a before');
await b();
console.log('a after');
};
a();
As we can see, the output order is a before, b, c then a after. So await had waited for b and continued waiting for c.
Basically I am trying to play around to understand more of async/await and promise in JS. I'm trying to make Hello comes in between finished! and third finish!!. So the best guess is, making second then asnyc and await for console.log('Hello'). I've tried both ways below but both are not working as expected.
Approach A
let promise = new Promise((res,rej)=>{
res();
});
promise.then(() => {
console.log('finished!')
}).then(() => {
setTimeout(async function(){
await console.log("Hello"); }, 3000); //async/await at setTimeout level
}).then(() => {
console.log('third finish!!')
})
Approach B:
let promise = new Promise((res,rej)=>{
res();
});
promise.then(() => {
console.log('finished!')
}).then(async () => { //async/await at thenlevel
await setTimeout(function(){
console.log("Hello"); }, 3000);
}).then(() => {
console.log('third finish!!')
})
You need the second section to be a Promise, and return it from the .then so that it's properly chained between the first and the third. setTimeout doesn't return a Promise, you have to explicitly construct a Promise instead:
let promise = new Promise((res,rej)=>{
res();
});
promise.then(() => {
console.log('finished!')
}).then(() => {
return new Promise(resolve => {
setTimeout(function(){
console.log("Hello");
resolve();
}, 1000);
});
}).then(() => {
console.log('third finish!!')
})
Or, using await, use await new Promise followed by the same Promise construction and the setTimeout:
let promise = new Promise((res, rej) => {
res();
});
promise.then(() => {
console.log('finished!')
}).then(async() => {
await new Promise(resolve => {
setTimeout(function() {
console.log("Hello");
resolve();
}, 1000);
});
}).then(() => {
console.log('third finish!!')
})
Another approach is to write an asynchronous setAsyncTimeout function (this hasn't been thoroughly tested, may need tweaks):
async function setAsyncTimeout(callback, interval) {
return new Promise( (resolve, reject) => {
setTimeout(() => {
try {
let inner = callback()
if (inner && inner.then) {
inner.then(resolve, reject)
} else {
resolve(inner)
}
} catch(e) {
reject(e)
}
}, interval)
})
}
Testing via your example:
let promise = new Promise((res,rej)=>{
res();
});
promise.then(() => {
console.log('finished!')
}).then( setAsyncTimeout(function(){
console.log("Hello"); }, 3000);
}).then(() => {
console.log('third finish!!')
})
Testing via your example (with another promise):
let promise = new Promise((res,rej)=>{
res();
});
promise.then(() => {
console.log('finished!')
}).then(async () => { //async/await at thenlevel
await setAsyncTimeout(function(){
console.log("Hello");
return setAsyncTimeout(() => console.log("world"), 3000)
}, 3000);
}).then(() => {
console.log('third finish!!')
})
Cleaner example:
let promise = new Promise((res,rej)=>{
res();
});
promise.then(() => {
console.log('finished!')
}).then(() => {
return setAsyncTimeout(() => { console.log("Hello"); }, 3000)
}).then(() => {
console.log('third finish!!')
})
I am just trying to understand how Promises and Async-Await work.
I want this to resolve by logging 1, 2, 3 in that order. Currently it logs 1, 3, 2.
I know the Promise doesn't really make sense here but in my program it has other uses so that needs to stay. The route from Caller function to Test also needs to stay (If need be you can change these but just know that they are there for a reason)
My question is how do I wait for the Caller function to resolve?
Here is my code:
function Test() {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('2');
resolve();
}, 2000);
})
}
function Caller() {
Test();
}
console.log('1');
Caller();
console.log('3');
I have tried what I understand, which is to make the Caller() function await the Test Promise, but that of course makes the Caller() function async and therefore we still get 1, 3, 2
async function Caller() {
await Test();
}
Is there maybe some way to use await without making the function async?
You can only await a function that returns a promise (well, not quite true, if it doesn't return a promise it creates a promise that resolves instantly)
You can only await when you are inside an asynchronous function
function test() {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('2');
resolve();
}, 2000);
})
}
async function caller() {
console.log('1');
await test();
console.log('3 (this is blocked awaiting the promise');
}
caller()
console.log("This is not blocked because caller is async");
This is a very straightforward, simple way of doing what you ask.
The await keyword can only be used inside functions
defined with async.
function test(ms) {
return new Promise((resolve, reject) => setTimeout(resolve, ms))
}
async function caller() {
console.log(1, ' - caller() started');
await test(2000).then(() => {
console.log(2, ' - test() resolved')
});
console.log(3, ' - delayed until "test()" has resolved');
return 4;
}
// wait for "caller()" to resolve
caller().then((result) => {
console.log(result, " - caller() finished")
});
console.log(5);
Here's a good article by Google which expands on the subject:
Async functions - making promises friendly.
Cite source.
here is how you could use functions like this:
function sleep(ms) {
return new Promise(r => {
setTimeout(() => r(), ms);
});
}
(async () => {
console.log(1);
await sleep(1000); // 1s
console.log(2);
await sleep(2000) // 2s
console.log(3)
})();
The previous answers are all correct but I just feel like this answer makes more sense. It is more accurate to the original question's code:
function Test() {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('2');
resolve();
}, 2000);
})
}
function Caller() {
return Test();
}
(async() => {
console.log('1');
await Caller();
console.log('3');
})();