await/async how to handle unresolved promises - javascript

How do you handle promises that do not resolve?
Example:
class Utils {
static async thisFunctionOnlyResolvesWhenPassed2AndNeverRejects(number: number) {
return new Promise((resolve, reject) => {
if(number === 2) {
resolve('ok')
}
})
}
}
console.log(await Utils.thisFunctionOnlyResolvesWhenPassed2AndNeverRejects(2))
// this will print "ok" because 2 is passed and the promise is resolved
console.log(await Utils.thisFunctionOnlyResolvesWhenPassed2AndNeverRejects(5))
// this will crash the program silently
uncaughtException and unhandledRejection return nothing when the promise is unresolved. Adding a try/catch around the await doesn't work (no errors). Finally, the only thing that works is using Promise.then instead of await.
Problem is the code base is riddled with async/await and Promises that sometimes resolve (depending on conditions)
Question: Is there a typescript flag I can add to detect a missing resolve/reject? or maybe an automated way to transpile all the async/await to use Promise.then?
When using a debugger, the program stops after the Promise and it is difficult to find which function/promise has a missing resolve/reject.
Rewriting all the async/await calls to use Promise.then is my last resort.

If you have promises that occasionally don't resolve or reject and that's not the way they are supposed to work (which it usually isn't), then you just have to fix that. There really is no work-around. The proper fix is to get down to the lowest level and fix the code so it reliably resolves or rejects every time.
This is not the proper fix, but implementing a timeout wrapper could help with debugging giving you a log message with some semblance of a stack trace for a timed out promise:
function rejectT(t) {
// create potential error here for better opportunity at stack trace
let e = new Error("Promise timed out");
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log(e);
reject(e);
}, t);
});
}
function timeout(p, t = 5000) {
return Promise.race([p, rejectT(t)]);
}
You can then wrap any promise such that instead of:
fn().then(...).catch(...)
You can use:
timeout(fn()).then(...).catch(...);
Or, if you want to set a custom timeout value:
timeout(fn(), 1000).then(...).catch(...);
Again, this is debugging code to help find the culprits that need fixing and to help test fixes, not to bandaid your code.
Rewriting all the async/await calls to use Promise.then is my last resort.
I don't see how this is going to help at all. If await never finishes, neither will promise.then(). They are exactly the same in that regard. If the promise never resolves or rejects, then the .then() handler will never get called either.
Problem is the code base is riddled with async/await and Promises that sometimes resolve (depending on conditions)
There's no shortcut here other than methodical code review to find suspect code that has code paths that may never resolve or reject and then building unit tests to test every function that returns a promise in a variety of conditions.
One likely source of code that never resolves or rejects are some of the promise anti-patterns. The precise reason some of them are anti-patterns is because they can be very easy to mess up. Here are a few references that might spike your sensitivity to suspect code:
Promise Anti-Patterns
Common Promise Anti-Patterns and How to Avoid Them
ES6 Promises: Patterns and Anti-Patterns

async function thisFunctionOnlyResolvesWhenPassed2AndNeverRejects(number) {
return new Promise((resolve, reject) => {
if (number === 2) {
resolve('ok')
} else {
reject('error:' + number)
}
})
}
(async() => {
try {
console.log(await thisFunctionOnlyResolvesWhenPassed2AndNeverRejects(2))
// this will print "ok" because 2 is passed and the promise is resolved
} catch (e) {
console.error(e);
}
try {
console.log(await thisFunctionOnlyResolvesWhenPassed2AndNeverRejects(5))
// this will crash the program silently
} catch (e) {
console.error(e);
}
})()

Related

How to load a imported function after another one in JavaScript [duplicate]

I'm doing some unit testing. The test framework loads a page into an iFrame and then runs assertions against that page. Before each test begins, I create a Promise which sets the iFrame's onload event to call resolve(), sets the iFrame's src, and returns the promise.
So, I can just call loadUrl(url).then(myFunc), and it will wait for the page to load before executing whatever myFunc is.
I use this sort of pattern all over the place in my tests (not just for loading URLs), primarily in order to allow changes to the DOM to happen (e.g. mimick clicking a button, and wait for divs to hide and show).
The downside to this design is that I'm constantly writing anonymous functions with a few lines of code in them. Further, while I have a work-around (QUnit's assert.async()), the test function that defines the promises completes before the promise is run.
I'm wondering if there is any way to get a value from a Promise or wait (block/sleep) until it has resolved, similar to .NET's IAsyncResult.WaitHandle.WaitOne(). I know JavaScript is single-threaded, but I'm hoping that doesn't mean that a function can't yield.
In essence, is there a way to get the following to spit out results in the correct order?
function kickOff() {
return new Promise(function(resolve, reject) {
$("#output").append("start");
setTimeout(function() {
resolve();
}, 1000);
}).then(function() {
$("#output").append(" middle");
return " end";
});
};
function getResultFrom(promise) {
// todo
return " end";
}
var promise = kickOff();
var result = getResultFrom(promise);
$("#output").append(result);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="output"></div>
I'm wondering if there is any way to get a value from a Promise or
wait (block/sleep) until it has resolved, similar to .NET's
IAsyncResult.WaitHandle.WaitOne(). I know JavaScript is
single-threaded, but I'm hoping that doesn't mean that a function
can't yield.
The current generation of Javascript in browsers does not have a wait() or sleep() that allows other things to run. So, you simply can't do what you're asking. Instead, it has async operations that will do their thing and then call you when they're done (as you've been using promises for).
Part of this is because of Javascript's single threadedness. If the single thread is spinning, then no other Javascript can execute until that spinning thread is done. ES6 introduces yield and generators which will allow some cooperative tricks like that, but we're quite a ways from being able to use those in a wide swatch of installed browsers (they can be used in some server-side development where you control the JS engine that is being used).
Careful management of promise-based code can control the order of execution for many async operations.
I'm not sure I understand exactly what order you're trying to achieve in your code, but you could do something like this using your existing kickOff() function, and then attaching a .then() handler to it after calling it:
function kickOff() {
return new Promise(function(resolve, reject) {
$("#output").append("start");
setTimeout(function() {
resolve();
}, 1000);
}).then(function() {
$("#output").append(" middle");
return " end";
});
}
kickOff().then(function(result) {
// use the result here
$("#output").append(result);
});
This will return output in a guaranteed order - like this:
start
middle
end
Update in 2018 (three years after this answer was written):
If you either transpile your code or run your code in an environment that supports ES7 features such as async and await, you can now use await to make your code "appear" to wait for the result of a promise. It is still programming with promises. It does still not block all of Javascript, but it does allow you to write sequential operations in a friendlier syntax.
Instead of the ES6 way of doing things:
someFunc().then(someFunc2).then(result => {
// process result here
}).catch(err => {
// process error here
});
You can do this:
// returns a promise
async function wrapperFunc() {
try {
let r1 = await someFunc();
let r2 = await someFunc2(r1);
// now process r2
return someValue; // this will be the resolved value of the returned promise
} catch(e) {
console.log(e);
throw e; // let caller know the promise was rejected with this reason
}
}
wrapperFunc().then(result => {
// got final result
}).catch(err => {
// got error
});
async functions return a promise as soon as the first await is hit inside their function body so to the caller an async function is still non-blocking and the caller must still deal with a returned promise and get the result from that promise. But, inside the async function, you can write more sequential-like code using await on promises. Keep in mind that await only does something useful if you await a promise so in order to use async/await, your asynchronous operations must all be promise-based.
If using ES2016 you can use async and await and do something like:
(async () => {
const data = await fetch(url)
myFunc(data)
}())
If using ES2015 you can use Generators. If you don't like the syntax you can abstract it away using an async utility function as explained here.
If using ES5 you'll probably want a library like Bluebird to give you more control.
Finally, if your runtime supports ES2015 already execution order may be preserved with parallelism using Fetch Injection.
Another option is to use Promise.all to wait for an array of promises to resolve and then act on those.
Code below shows how to wait for all the promises to resolve and then deal with the results once they are all ready (as that seemed to be the objective of the question); Also for illustrative purposes, it shows output during execution (end finishes before middle).
function append_output(suffix, value) {
$("#output_"+suffix).append(value)
}
function kickOff() {
let start = new Promise((resolve, reject) => {
append_output("now", "start")
resolve("start")
})
let middle = new Promise((resolve, reject) => {
setTimeout(() => {
append_output("now", " middle")
resolve(" middle")
}, 1000)
})
let end = new Promise((resolve, reject) => {
append_output("now", " end")
resolve(" end")
})
Promise.all([start, middle, end]).then(results => {
results.forEach(
result => append_output("later", result))
})
}
kickOff()
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Updated during execution: <div id="output_now"></div>
Updated after all have completed: <div id="output_later"></div>

Difference between Promise and async/await

What is the difference between the two functions ?
function src() {
return new Promise((resolve, reject) => {
setTimeout(() => resolve(console.log("done! 1 ")), 4000);
});
}
async function src() {
setTimeout(() => console.log("done! 1 "), 4000);
}
The second one will return a Promise that resolves immediately.
The first one will return a Promise that resolves after 4 seconds.
In the first one, once the function is called a promise is returned with resolved state set in a timeout. So when the 4 sec timer ends (ofc without any errors) the resolved function triggers with text logged to the console.
Second one will too return a promise but of no certain use. On being called, it will just trigger the timer to print text after 4 sec. No promise functionality is used here.
Async/Await is just syntactic sugar for promises. Async/Await implicitly uses Promises. Async/Await just makes working with Promises easier.
That being said, your second functions doesn't make use of Async/Await properly. There's no await statement, but it's impossible to use an await statement directly with setTimeout anyway.
So, if you still want to use Async/Await you would have to write your own timeout function that would resemble your first function.
function timeout(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function src() {
await timeout(4000);
console.log("done! 1 ");
}
Whenever you create new Promise you get to parameters resolve & reject. Whenever its success case you resolve on failure you reject. In case of resolve it will go to then & in case of reject it will go to catch. Promise is more over like real world promise (it could either be completed [resolved] or broken [reject]).
Though async & await helps you do asynchronous operations in JS. Whenever in async function it encounters await it will wait for that code to be executes and then will move to next line.
Refer to this video for better understanding along with example.

Can Promise.race be used for catching e.g. an error event while waiting for a Promise to resolve/reject?

I have a multiplayer card game where a client plays a round.
The function to play this round let's say playRound returns a Promise if the round was successfully played or something went wrong for example the client tried to cheat.
What I want to do now is to catch an event from an EventEmitter if the client errors or leaves unexpectedly. Because it would be nice to reuse the catch handler of the rejected play round promise I thought of promisifying the event and then just do a Promise.race() with the playRound function so only if the event occurs and if the Promise is still pending it should reject.
My code which is highly simplified and should just help to understand the problem looks like this:
// function only rejects if on error handler gets called and it never resolves
// underscore param should indicate that the resolve function is never used
const onClientError = client => new Promise((_, reject) => {
const handler = () => {
reject(Error(`client encountered an error`));
};
client.api.onError(handler);
});
try {
const round = await Promise.race([
playRound(client),
onClientError(client),
]);
// check for unexpected behaviour
if (!round) {
throw Error('played round is undefined');
}
// return the result
return round;
} catch (error) {
// do something if rejected or on client error
}
In my opinion it should be no problem to use it like that but I have a feeling that there is a better way to solve this. But the state should always be valid because round either throws or is defined.
My question is now, is it bad practice to do something like this(a promise that never resolves in combination with a promise race) or do you know of a better way to solve this problem?

How does using async/await differ from using Promises?

Recently I started using (Async & Await). Before this, I used Promise to make my process Asynchronous. Like:
example.firstAsyncRequest()
.then(firstResponse => {
return example.secondAsyncRequest(firstResponse)
})
.then(secondResponse => {
return example.thirdAsyncRequest(secondResponse)
})
.then(result => {
console.log(result)
})
.catch(err => {
console.log(err)
})
Now I am achieving this like:
try {
const firstResponse = await example.firstAsyncRequest();
const secondResponse = await example.secondAsyncRequest(firstResponse);
const thirdAsyncRequest = await example.thirdAsyncRequest(secondResponse);
console.log(thirdAsyncRequest)
}
catch (error) {
// Handle error
}
In both, the code-block method executes one after another and finally throws an error if any and gets caught by catch block. My question is, is this only a difference of syntax? Please explain or suggest me any link to understand this better.
Thank You
Is there only difference of syntax?
Yes. Your examples are functionally equivalent except that your second example is missing
console.log(thirdAsyncRequest);
...after the third await. (That variable really should be result to match the first code block, or thirdResponse to match the other two response variables).
async/await is syntactic sugar around promise creation and consumption. It's really helpful sugar, but that's all it is. async functions return promises. await expressions let you wait for a promise to settle, either getting the fulfillment value if it's fulfilled or throwing an error if it's rejected. (Since rejections are errors, you can use try/catch to handle them.) An uncaught error in an async function (whether a synchronous error or a promise rejection observed by await) causes the promise the async function returned to be rejected with that error. Otherwise, the function's promise is resolved to whatever the function's code returns: if it returns a non-thenable, the promise is fulfilled with that value; if it returns a thenable, the promise is fulfilled or rejected based on the settlement of that thenable.
(Re "resolve" vs. "fulfill" and such, I've written up this post on promise terminology.)

Do I have to fulfil my JavaScript promises?

In a Node.js environment if I do this:
var doNoResolve = true;
function a() {
return new Promise(resolve => {
if (doNotResolve) {
return
}
resolve(10);
});
}
a().then(() => {
// I don't want this getting fired
});
On an incoming request, is this a memory leak? If I was using a plain old callback everything would turn out just fine if I didn't execute whatever callback was supplied, but this feels like it might not be... the very name promise implies this is somewhat wrong.
If I had to I could return a "fake promise" (return { then: () => {} }) inside function a() rather than a "real promise" if doNotResolve was true, but that feels a bit gross.
The particular use-case is that of an isomorphic React.js application where I don't want HTTP requests actually getting made (but I do want my stores to update to a state that causes, say, a loading icon to appear).
Why would you do that instead of rejecting?
The benefit of promises is that they allow both resolving and rejecting, which:
Doesn't fire the then handler (unless you provide two callbacks, which is considered bad practice)
Does fire the catch handler, which explicitly handles errors
Still fire the finally handler
You can simply do:
function a() {
return new Promise((resolve, reject) => {
if (doNotResolve) {
reject(new Error('Oh noes!'));
}
resolve(10);
});
}
Any good Promise implementation will give you a stacktrace from the location you called reject to help you debug async code, as well as calling any catch/finally handlers:
a().then(val => {
console.log('Got data:', val);
}).catch(err => {
console.error(err);
}).finally(() => {
console.log('Done!');
});
Never rejecting or resolving a promise will, depending on your implementation, leave it on the stack of pending promises and very likely throw or log an error when your page unloads or the node promise exits. I know Bluebird will complain if you've left any promises pending, since it typically indicates a bug within the async part of your code.

Categories

Resources