This question already has answers here:
How to turn this callback into a promise using async/await?
(2 answers)
Closed 3 years ago.
I have two functions that are written with promises:
const resolvedDelay = (value, ms) => new Promise(resolve => setTimeout(() => resolve(value),ms));
const rejectedDelay = (value, ms) => new Promise((resolve,reject) => setTimeout(() => reject(value),ms));
I try to rewrite them via async/await. This is my wrong attempt:
const resolvedDelay = async (value, ms) => setTimeout(() => value,ms); // I haven't reference to `resolve` here... :(
const rejectedDelay = async (value, ms) => setTimeout(() => {throw new Error(value)},ms);
How to do it right?
Usually something like this is done to convert the setTimeout into a reusable promise, which is then awaitable.
const delay = time => new Promise(res => setTimeout(res, time));
const resolvedDelay = async (value, ms) => {await delay(ms); return value;};
const rejectedDelay = async (value, ms) => {await delay(ms); throw Error(value);};
You have to have a promise first in order to do anything useful with await. And, since setTimeout() doesn't create a promise and doesn't resolve or reject a promise, you HAVE to create a promise and tie it to the setTimeout() callback just like you did in your first code block.
Your second code block just calls setTimeout() and immediately returns. Wrapping it in an async makes it return a promise, but that promise is just immediately resolved when the function returns after calling setTimeout(). So, you have to be resolving or rejecting a promise when the setTimeout() callback fires and there is no way to do that with just an async function wrapper around it.
Therefore, there's no real use for async/await in creating your two functions. Your first group of functions where you manually create a promise is the way to go here.
Of course, the caller can use await with your first set of functions just fine without change.
This is how I would do it, I don't know of a way of doing it that would make it remain as an arrow function though.
function resolvedDelay(value, ms) {
return new Promise(resolve => {
setTimeout(() => {
resolve(value);
}, ms);
});
}
function rejectedDelay(value, ms) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(value);
}, ms);
});
}
async function callFunctions() {
const resolved = await resolvedDelay();
const rejected = await rejectedDelay();
// Do whatever you want with them now
}
Related
This question already has answers here:
Why does nodejs stop execution of while true loop inside async function
(3 answers)
Closed 28 days ago.
I have a sample code on TS playground represents my problem.
In an async function, I log the result after await for the promise, but only the code inside promise run, not the log outside of it. Could someone explain this problem?
Here is the code:
const asyncFnc = async () => {
let result = false;
await new Promise(resolve => {
setTimeout(() => {
// This log worked
console.log('waited 5s');
result = true;
}, 5000);
});
// This log did not worked
console.log(result);
}
asyncFnc();
And the result:
await sends the parent function to sleep until the promise on the right hand side settles (i.e. resolves or rejects).
Your promise never resolves or rejects. (i.e. you don't call resolve, make use of the second argument, or throw an exception).
Thus the parent function sleeps forever.
The idiomatic way to write this would be to avoid setting variables in the wider scope as a side effect, and just resolve with the values instead.
const asyncFnc = async () => {
const result = await new Promise(resolve => {
setTimeout(() => {
console.log('waited 5s');
resolve(true);
}, 5000);
});
console.log(result);
}
asyncFnc();
You need to call resolve() in your timeout
This question already has answers here:
What is the difference between a function call and function reference?
(6 answers)
How can I pass a parameter to a function without it running right away?
(3 answers)
Closed last year.
Hey, i am trying to return this console after 1000 milli sec using this promise, but for some reason it consoles before ending the setTime out. Any idea how I can get the console.log to happen after the timeOutPromise is finished?
const timeOutPromise = () => new Promise(resolve => { setTimeout(() => { resolve(); }, 1000); });
const thisPromise = (num1, num2) => new Promise((resolve, reject) => {
timeOutPromise()
.then(resolve(console.log(num1 + num2)))
.catch(reject(Error));
});
thisPromise(1, 2);
Your code is calling console.log synchronously when the promise is set up. You need to pass a callback to then, not the result of console.log(). Further, if you already have a promise, no need to wrap it in a promise constructor, just use chaining.
const timeOutPromise = () => new Promise(resolve => { setTimeout(() => { resolve(); }, 1000); });
const thisPromise = (num1, num2) => timeOutPromise()
.then(() => console.log(num1 + num2))
thisPromise(1, 2);
I want to resolve a promise when an event happens in a different function
const trigger = function() {}
const eventHandler = async function() {
while(true) {
await new Promise (resolve => {
}
// Code when the promise fulfills.
}
}
const cleaner = function() {
trigger()
}
cleaner()
You can do that really easily by re-assigning the trigger:
let trigger = () => {}
const eventHandler = async function() {
while(true) {
await new Promise (resolve => {
trigger = resolve
// ^^^^^^^^^^^^^^^^^
}
// Code when the promise fulfills.
}
}
const cleaner = function() {
trigger() // calls resolve to fulfill the currently waited-for promise
}
eventHandler() // start waiting
cleaner()
However, notice that this is generally regarded as a bad practice, you should start whatever leads to the external event, and especially installing the event listener, inside the new Promise executor callback, where you trivially have access to the resolve function.
Below is an example of how you might go about making a promise cancelable. We're using a helper function makeCancelable() that takes a promise, and returns a different promise and a cancel function. There's no way to just "cancel" an existing promise, especially when you don't have control over how the promise is made, but what you can do it wrap the existing promise in a new one that's behaves just like the original, but is also ready to resolve on command.
// Helper function that just waits for a timeout
const wait = ms => new Promise(resolve => setTimeout(resolve, ms))
function makeCancelable(promise) {
let resolveWrappedPromise
return {
promise: new Promise((resolve, reject) => {
resolveWrappedPromise = resolve
promise.then(resolve, reject)
}),
cancel: value => resolveWrappedPromise(value),
}
}
cancelPromise = () => {} // function used by onClick event
async function eventHandler() {
while (true) {
const { promise, cancel } = makeCancelable(wait(1000).then(() => 'Success!'))
cancelPromise = cancel
console.log(await promise)
}
}
eventHandler()
<button onclick="cancelPromise('Canceled!')">Cancel!</button>
In this code example, "Success!" will print out every second - unless you push the button to cancel the current promise. Repeated pushes of the button will delay "Success!" from being printed indefinably, because the promise was canceled and provided with the value "Canceled!" when cancellation occurred.
Use the waitFor method of the EventEmitter2 package (Live demo).
import EventEmitter2 from "eventemitter2";
const emitter = new EventEmitter2();
(async () => {
const data = await emitter.waitFor("test");
console.log("emitted", data);
})();
setTimeout(() => emitter.emit("test", 1, 2, 3), 1000);
Is there any typescript config option or some workaround to check if there is no resolve called in new Promise callback?
Assume I have a promise
new Promise(async (resolve, reject) => {
try {
// do some stuff
// but not calling resolve()
} catch (e) {
reject(e)
}
})
I want typescript to warn me that I did not call resolve(). Is it possible?
I know that I can use noUnusedParameters, but there are a couple of situations where I still need unused parameters (e.g. request inside of express.Hanlder, where I only use response, etc.)
No, that is not possible. Knowing whether code calls a certain function (resolve in this case) is just as hard as the halting problem. There is proof that no algorithm exists that can always determine this.
To illustrate, let's assume that the algorithm for determining whether a function calls resolve exists, and is made available via the function callsResolve(func). So callsResolve(func) will return true when it determines that func will call resolve (without actually running func), and false when it determines that func will not call resolve.
Now image this func:
function func() {
if (!callsResolve(func)) resolve();
}
... now we have a paradox: whatever this call of callsResolve returned, it was wrong. So for instance, if the implementation of callsResolve would have simulated an execution of func (synchronously) and determines that after a predefined timeout it should return false, the above is a demonstration of a function that calls resolve just after that timeout expired.
The closest you can get to a compile time check is to use async / await syntax.
If you don't want to use that, you could timeout your promises, though you would have to do that with each of your promise after / when you are creating them.
A solution could look like this:
export const resolveAfterDelay = (timeout: number) => new Promise((r) => setTimeout(r, timeout));
export const rejectAfterDelay = async (timeout: number) => {
return new Promise((resolve, reject) => setTimeout(() => reject(`Promise timed out as resolve was not called within ${timeout}ms`), timeout));
};
export const timeoutPromise = <T>(timeout: number) => async (p: Promise<T>): Promise<T> => {
return Promise.race([p, rejectAfterDelay(timeout)]);
};
const timeoutAfter1s = timeoutPromise(1e3);
const timeoutAfter10s = timeoutPromise(10e3);
timeoutAfter10s(resolveAfterDelay(3e3)).then(success => console.log("SUCCESS IS PRINTED")).catch(console.error); // works
timeoutAfter1s(resolveAfterDelay(3e3)).then(success => console.log("NEVER REACHED")).catch(console.error); // aborts
const neverResolvingPromise = new Promise(() => {
});
timeoutAfter1s(neverResolvingPromise).catch(console.error); // promise never resolves but it will be rejected by the timeout
It makes use of Promise.race. Basically, whatever first resoves or rejects will be returned. We want to always reject a Promise if it does not resolve in time.
You would always have to wrap your Promise on creation like
timeoutAfter10s(new Promise(...));
And you would have to adapt the timeout according to your use case.
I was wondering what is the proper way to call a promise after another promise resolves. I know we can use async await to create functions which will resolve a promise. I was wondering which form of handling promises is consider proper practice, or is it good practice to create generators instead? consider the following code:
const fetchSomething = () => new Promise((resolve) => {
setTimeout(() => resolve(console.log('future value')), 500);
});
const fetchSomethingElse = () => new Promise((resolve) => {
setTimeout(() => resolve(console.log('future value dueeee')), 3000);
});
const get = () => {
return fetchSomething().then(function(){
fetchSomethingElse()
});
}
get();
or
const fetchSomething = () => new Promise((resolve) => {
setTimeout(() => resolve({resolve: true}), 500);
});
const fetchSomethingElse = () => new Promise((resolve) => {
setTimeout(() => resolve({resolve: true}), 3000);
});
const get = async function() {
const fet = await fetchSomething();
const fet2 = await fetchSomethingElse();
};
get();
Either one is fine. Your choice.
In the first you're nesting .then() handlers. In the second, you're using the newer await to sequence them. More people are moving to await because it appears to be simpler code for sequencing operations (assuming you do proper error handling), though in this case, they are pretty similar in complexity, particularly with the simplification suggested below so it's really up to your own personal coding style.
What is missing in both is that get() just returned a promise so you need to use .then() and .catch() with it to get the value and catch any errors.
Also, something that is missing in the first is that you aren't returning the second promise which means the caller won't know when the second operation is done.
Your first can be simplified and fixed up like this:
const get = () => {
return fetchSomething().then(fetchSomethingElse);
}
get().then(val => {
// done here
}).catch(err => {
// error here
});
As Pointy mentioned, you don't "call a promise". You "call a function that returns a promise". Promises are objects. They are not callable.
Probably what your title could be rewritten to is: "Correct way to sequence two asynchronous operations that each return a promise".
For completeness, if your two async operations don't depend upon one another, then you don't have to manually sequence them. You can start them both and then monitor when both are done. This will sometimes get a faster end-to-end response.
You can do that using Promise.all():
const get = function() {
return Promise.all([fetchSomething(), fetchSomethingElse()]).then(results => {
// process results array and then return final value
// results[0] is result from fetchSomething, results[1] is result from fetchSomethingElse
return finalVal;
});
}
Both are fine, but you are making a common mistake in the top example (and maybe it's just because of the simplification of the code for the question). You are returning the promise from get, but you are not returning the promise from the then. This means the caller of get won't know when both promises have resolved. Consider:
const fetchSomething = () => new Promise((resolve) => {
setTimeout(() => resolve(console.log('future value')), 500);
});
const fetchSomethingElse = () => new Promise((resolve) => {
setTimeout(() => resolve(console.log('future value dueeee')), 3000);
});
const get = () => {
return fetchSomething().then(function(){
fetchSomethingElse()
});
}
// we don't when fetchSomethingElse is done
get().then(() => console.log("done"));
Also there's another option you might consider since the second promise doesn't depend on the output of the first. Call them in parallel:
const get = () => {
return Promise.all([fetchSomething(), fetchSomethingElse() ])
}
In this case one can start before the other is finished and the whole operation should be faster.
It's important to remember that in Promise-based patterns you're using functions that return Promises. Promises are passed in resolve and reject arguments (which are themselves functions). What you resolve with, is what gets exectuted in the .then() phase, and what you reject with gets exectuted in the .catch() phase.
To handle Promises in sequence, you're passing your values into the top-level function that wraps the Promise.
so...
const p1 = () => {
return new Promise((resolve,reject) => {
window.setTimeout(() => {
resolve('future value one');
},500);
});
};
const p2 = (v1) => {
return new Promise((resolve,reject) => {
window.setTimeout(() => {
const v2 = 'future value two';
resolve({v1,v2});
},500);
});
};
p1().then(p2).then(console.log);