Returning another aysnc function in resolve - javascript

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.

Related

How does Javascript Promise work with setTimeOut [duplicate]

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"));

Proper use of async JS to ensure function calls wait for previous functions to complete (resolve?)

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()

Reject all functions if one is rejected

I have a similar problem in dialogflow fulfillment where I need to book any appointments on the Google calendar. I would reject all functions p1, p2 and p3 if only one of them is rejected. In the code below, although p2 is rejected, the others p1 and p3 are executed (I wish all functions p1, p2 and p3 were not performed).
function f1() {
return Promise.all([p1(), p2(), p3()])
.then(value => {
alert('ok');
})
.catch(err => {
console.log('err: ' + err);
});
}
function p1() {
new Promise((resolve, reject) => {
setTimeout(resolve, 1000, alert("one"));
});
}
function p2() {
new Promise((resolve, reject) => {
reject('reject');
});
}
function p3() {
new Promise((resolve, reject) => {
setTimeout(resolve, 3000, alert("three"));
});
}
f1();
Well it contains a lot of code to implement it so I would give short instructions.
You need to have a way to reject your request or whatever you are doing. For examples with axious we can use CancelToken to cancel HTTP request.
Now you need to subscribe on each request and cancel the request or whatever you are using.
It is not clear what exactly you need. Functions can not be rejected or not executed if you run them in parallel. You can only notify the internal function code that the cancel operation was requested from the outside. We don't know what async operations are performed inside your async functions. Demo
import { CPromise } from "c-promise2";
function makePromise(ms, label) {
return new CPromise((resolve, reject, { onCancel }) => {
setTimeout(resolve, ms);
onCancel(() => console.log(`onCancel(${label})`));
});
}
CPromise.all([
makePromise(2000, "one"),
makePromise(1500, "two").then(() => {
throw Error("Oops");
}),
makePromise(4000, "three")
]).then(
(v) => console.log(`Done: ${v}`),
(e) => console.warn(`Fail: ${e}`)
);
onCancel(one)
onCancel(three)
Fail: Error: Oops
The problem is you're not returning anything from p1, p2, p3. So when you call Promise.all([p1(), p2(), p3()]) which is actually calling with Promise.all([undefined, undefined, undefined])(resolves anyway) which does not have a rejection. That's why you're not seeing the error.
Add return in your functions.
function f1() {
return Promise.all([p1(), p2(), p3()])
.then(value => {
alert('ok');
})
.catch(err => {
console.log('err: ' + err);
});
}
function p1() {
return new Promise((resolve, reject) => {
setTimeout(resolve, 1000);
});
}
function p2() {
return new Promise((resolve, reject) => {
reject('reject');
});
}
function p3() {
return new Promise((resolve, reject) => {
setTimeout(resolve, 3000);
});
}
f1();
Remember Promises are not cancellable, if you really want cancel execution part, you can try something like this. I don't guarantee this works all the time and I don't think good idea to do in this way.
const timers = []
function f1() {
return Promise.all([p1(), p2(), p3()])
.then(value => {
alert('ok');
})
.catch(err => {
console.log('err: ' + err);
timers.forEach((timerId) => clearTimeout(timerId))
});
}
function p1() {
return new Promise((resolve, reject) => {
const timerId = setTimeout(() => {
alert(1)
resolve()
}, 1000);
timers.push(timerId)
});
}
function p2() {
return new Promise((resolve, reject) => {
reject('reject');
});
}
function p3() {
return new Promise((resolve, reject) => {
const timerId = setTimeout(() => {
alert(2)
resolve()
}, 3000);
timers.push(timerId)
});
}
f1();

Wait for a functions to finish in sequence Javascript

I have three functions prints 20,30,10 as per setTimeout how should i make them print 10,20,30 order using promise
How to write these callbacks to print right order.
P.S. : This is not a duplicate question. Thanks !
var A = function(callback) {
setTimeout(function() {
console.log(10)
callback();
}, 2000);
};
var B = function(callback) {
console.log(20);
callback();
};
var C = function(callback) {
setTimeout(function() {
console.log(30)
callback();
}, 200);
};
function runTask() {
var wait = ms => new Promise ((resolve,reject) => setTimeout(resolve, ms))
var FuncA = wait();
FuncA.then(() => A(function () {}))
. then(() => B(function () {}))
.then(() => C(function () {}));
}
runTask();
I'm not 100% sure I understood your question. But, here it is based on what I understood. You weren't doing anything with the callback so I didn't pass them.
In your code function B didn't have a delay.
function delayAsync(ms) {
return new Promise(p_resolve => setTimeout(p_resolve, ms));
}
async function A(callback) {
await delayAsync(2000);
console.log(10);
if (callback instanceof Function) {
callback();
}
}
async function B(callback) {
console.log(20);
if (callback instanceof Function) {
callback();
}
}
async function C(callback) {
await delayAsync(200);
console.log(30);
if (callback instanceof Function) {
callback();
}
}
function runTask() {
return new Promise(async (resolve, reject) => {
await A();
await B();
await C();
resolve();
});
}
runTask().then(() => console.log('done'));
If you want to stick with Promises, you could create a helper function that performs a setTimeout but returns a Promise. This will preserve the order of console logs:
const setTimeoutAsync = (fn, ms) => new Promise(resolve => setTimeout(() => resolve(fn()), ms));
var A = function(callback) {
return setTimeoutAsync(() => {
console.log(10)
callback();
}, 2000);
};
var B = function(callback) {
console.log(20)
callback();
};
var C = function(callback) {
return setTimeoutAsync(() => {
console.log(30)
callback();
}, 200);
};
function runTask() { // refactored since A now returns a Promise
return A(() => {})
.then(() => B(() => {}))
.then(() => C(() => {}));
}
runTask();
Alternatively, if you'd like a clean solution and don't mind adding a third party module, you could use async-af, a library for chainable asynchronous JavaScript methods that I maintain:
const setTimeoutAsync = (fn, ms) => new Promise(resolve => setTimeout(() => resolve(fn()), ms));
var A = function(callback) {
return setTimeoutAsync(() => {
console.log(10)
callback();
}, 2000);
};
var B = function(callback) {
console.log(20)
callback();
};
var C = function(callback) {
return setTimeoutAsync(() => {
console.log(30)
callback();
}, 200);
};
// to run in parallel you would omit `series`, but
// since you want to run the tasks in order include it:
function runTask(...tasks) {
return AsyncAF(tasks).series.forEach(task => task(() => {}));
}
runTask(A, B, C);
<script src="https://unpkg.com/async-af#7.0.11/index.js"></script>

Understanding Promise and Await

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');
})();

Categories