Is there any way to define that a function explicitly can throw, obviously any function can throw an error. But I'd like to explicitly define that a function is designed to throw and possibly not return a value at all.
async function falseThrow (promise: Promise<any>, error): any {
let value: any = await promise
if (!value) throw error
return value
}
As Nat Mote highlighted in her answer, there's no way of encoding checked exceptions in flow.
However, if you're open to change the encoding a bit, you could do something equivalent:
async function mayFail<A, E>(promise: Promise<?A>, error: E): E | A {
let value = await promise
if (!value) {
return error
}
return value
}
Now flow will force the user to handle the error:
const p = Promise.resolve("foo")
const result = await mayFail(p, Error("something went wrong"))
if (result instanceof Error) {
// handle the error here
} else {
// use the value here
result.trim()
}
If you try to do something like
const p = Promise.resolve("foo")
const result = await mayFail(p, Error("something went wrong"))
result.trim() // ERROR!
flow will stop you, because you haven't checked whether result is an Error or a string, so calling trim is not a safe operation.
Flow doesn't support checked exceptions. It makes no attempt to model which functions may throw or what sorts of errors they may throw.
Related
I'm using Promise.reject
I've got this warning: Unhandled promise rejection warning: version is not released
how can I solve this warning ? I'm trying to use try and catch
Thanks for your help
public async retrieveVersionFromJira(versionName: string):
Promise<ReleaseVersion> {
const searchVersionsUri = config.jiraApiUri + 'versions';
const jsonResp = await this.jiraClient.get(searchVersionsUri);
const version: any = jsonResp.find(version => {
if (version.name == versionName) {
if (version.released == true) {
try{
return Promise.reject("version " + versionName + " is not released");
}
catch{
return Promise.reject("error test")
}
}
}
});
if (!version) {
return Promise.reject("missing version " + versionName + " on jira");
}
return new ReleaseVersion(version.id, version.name, version.released);
}
There are probably two problems:
Not handling rejection. This problem isn't in retrieveVersionFromJira, it's in the code using it. That code needs to handle the fact that it may reject its promise. Apparently, the code using it is only handling success, not failure.
One of the basic rules of promises (and thus, async functions, which return promises) is that you must either handle rejection (errors), or pass the promise on to a calling function that will handle rejection.
If you're calling it from an async function, that function will automatically pass on rejection to its caller (which should either pass it on or handle it). If you're using a top-level async function, it needs to never reject (by using try/catch to catch all errors/rejections that occur within it), like this:
// If this is the top level
(async function() {
try {
const version = retrieveVersionFromJira("name");
// ...use `version`...
} catch {
// Handle/report error
}
})();
If you're calling it from a non-async function, that function also must either return the promise chain to its caller (which should either pass it on or handle rejection) or handler rejection, e.g.:
// Pass it on
function someFunction() {
return retrieveVersionFromJira("name")
.then(version => {
// ...use the result...
});
}
// Or handle rejection
function someFunction() {
retrieveVersionFromJira("name")
.then(result => {
// ...use the result...
})
.catch(error => {
// Handle/report the error
});
}
The code in retrieveVersionFromJira calling jsonResp.find is incorrect. You've said that jsonResp is an array¹. Array.prototype.find expects the callback to return a truthy or falsy value indicating whether the current entry is the one you want to find. Your code attempts to return from retrieveVersionFromJira from within the callback, which it can't do. You also have if (version.released == true) followed by return Promise.reject("version " + versionName + " is not released");, which doesn't seem to make sense. You probably wanted:
const version: any = jsonResp.find(version => version.name === versionName);
if (version && !version.released) {
return Promise.reject("version " + versionName + " is not released");
}
...but see the note under the line below about return Promise.reject(...) not being the best way to handle rejecting the promise from an async function.
¹ ...in which case, it isn't JSON. JSON is a textual notation for data exchange. If you're dealing with JavaScript source code, and not dealing with a string, you're not dealing with JSON.
Side note: Although it isn't the problem, the code in retrieveVersionFromJira shouldn't be using Promise.reject. See this question's answers, the way to reject the promise from an async function is to use throw. Everywhere you've used return Promise.reject(x); you should be using throw x;. Also, since rejections are errors, it's usually best to use Error instance (e.g., throw new Error("missing version " + versionName + " on jira");.
So I want to know how to make sure that my Node application will crash if it comes upon a programmer error(undefined variable, reference error, syntax error...). However, if I am using promise chains then the final catch() will catch all possible errors including programmer errors.
For example:
PromiseA()
.then((result) => {
foo.bar(); //UNDEFINED FUNCTION HERE!!!!!
return PromiseB(result);
})
.catch(
//handle errors here
)
Now the catch() statement will also catch the really bad error of an undefined function and then try to handle it. I need a way for my program to crash when it comes up against errors like these.
EDIT: I also just realized that even if I throw an error in the last catch it will just be consumed by the promise chain :-[. How am I supposed to deal with that?
Basically, what you want to do is to handle those errors that you can potentially recover from. These errors are usually something you throw in your code. For example, if an item is not found in a DB some libraries will throw an Error. They'll add a type property or some other property to differentiate the different type of errors.
You can also potentially subclass the Error class and use instanceof to differentiate each error.
class myOwnError extends Error {}
Then:
Prom.catch(err => {
if(err instanceof myOwnError){ /* handle error here */ }
else { throw err; }
});
If you want to avoid if/chains, you can use a switch on error.constructor:
switch(err.constructor){
case myOwnError:
break;
case someOtherError:
break;
default:
throw err;
}
You can also use an a Map or regular objects by creating functions for each possible error and storing them. With a Map:
let m = new Map();
m.set(myOWnError, function(e){ /*handle error here*/ });
m.set(myOtherError, function(e){ /*handle other error here*/ });
Then just do:
Prom.catch(err => {
let fn = m.get(err.constructor);
if(fn){ return fn(err); }
else { throw err; }
});
Disclaimer: Below is a description what we do at the company I work. The package linked is written by us.
What we do is to catch all errors and sort them into programmer and operational errors.
We've made small library to help us: https://www.npmjs.com/package/oops-error
For promise chains we use:
import { programmerErrorHandler } from 'oops-error'
...
export const doSomething = (params) => {
somePromiseFunction().catch(programmerErrorHandler('failed to do something', {params}))
}
It marks the error as programmer error, adds 'failed to do something' as error message and adds the params as a context (for debugging later)
For errors that we know that can come up (person not found, validEmail, etc) we do something like
import { Oops } from 'oops-error'
export const sendEmail = (email) => {
if(!isValidEmail(email)) {
throw new Oops({
message: 'invalid email',
category: 'OperationalError',
context: {
email,
},
})
}
...
}
At every level we show the error messages of Operational Errors. So a simple
.cath(e => {
if (e.category == 'OperationalError') {
// handle the gracefully
}
else {
throw e // We will tackle this later
}
}
And at the end of our request in express we have our final error handler, where catch the error, check if its operational and then show the error message, but not the actual context. If its a programmer error we stop the process (not ideal, but we don't want the user to keep messing with broken code)
So recently I was asked a question :
Is there a way to throw an error without using throw in javaScript ?
As far as I knew about errors, there was only one way to throw an error in JavaScript and that was using throw statement in JavaScript like so :
var myFunc = () => {
// some code here
throw 'Some error' // in a conditional
// some more code
}
try {
myFunc()
}catch(e) {
console.log(e)
}
And not knowing any other way I said No, there is no other way. But now I'm wondering whether I was right ?
So the question is whether or not you can throw a custom error in JavaScript without using throw
Restrictions :
Kindly no using eval , Function.
Don't use throw in your code
Additional :
If you can throw an error without using the word Error
Generators do have a throw method that is usually used to throw an exception into the generator function code (at the place of a yield expression, similar to next), but if not caught it bubbles out of the call:
(function*(){})().throw(new Error("example"))
Of course, this is a hack and not good style, I have no idea what answer they expected. Especially the "no division by zero" requirement is sketchy, since division by zero does not throw exceptions in JS anyway.
If all you want to do is throw an error then just do an invalid operation. I've listed a few below. Run them on your browser console to see the errors (tested on chrome and firefox).
var myFunc = () => {
encodeURI('\uD800'); // URIError
a = l; // ReferenceError
null.f() // TypeError
}
try {
myFunc()
}catch(e) {
console.log(e);
}
function throwErrorWithoutThrow(msg) {
// get sample error
try {
NaN();
} catch (typeError) {
// aquire reference to Error
let E = typeError.__proto__.__proto__.constructor;
// prepare custom Error
let error = E(msg);
// throw custom Error
return Promise.reject(error);
}
}
throwErrorWithoutThrow("hi")
/* catch the error, you have to use .catch as this is a promise
that's the only drawback, you can't use try-catch to catch these errors */
.catch((e) => {
console.log("Caught You!");
console.error(e);
});
I think, if you want to use try...catch blocks, you will need to throw something to get to the catchpart. You can use pretty much everything that fails with an error to do that (like mentioned in the other posts).
If at some point, you want to run-or-die without having to write the throw statement yourself, you can always do an assertion:
const myFunction = () => {
try {
assert.fail();
console.log(`Did not work :)`);
} catch (e) {
console.log(`OK`);
}
};
Of course I would rather try to assert something positive (more Zen), that I need in order to continue.
const myTypeErr = () => `This is a Custom Err Message... \nand it`()
try {
myTypeErr()
} catch(e) {} // caught
myTypeErr() // Uncaught TypeError: "This is a Custom Err Message...
// and it" is not a function
I need to write a function that returns a promise, where first I call a synchronous function A() which returns some result.
Then return a function B(result) where B is a promise which takes in the result of A().
If either function fails I want the same error function C(error) to get called where C is a promise.
What is the best way of writing this. This is what I have but think there is obvious way I am missing
function() {
try {
var result = A();
return B(result)
.catch(function(error) {
return C(error);
});
}
catch(error) {
return C(error);
}
}
It seems wrong combining synchronous try and catch with a promise .catch and also wrong there are two different places I need to call C(error).
A() throws an error rather than returning an error code.
You don't say exactly how A() fails. It could either throw or it could return an error result. I'll show a scheme for both. The key to a mix of sync and async is to always return a promise. This will give you a consistent interface for teh caller no matter how the function succeeds or fails.
If you are only worried about A() throwing an exception and it doesn't return an error code, then you can do this:
function someFunction() {
try {
var result = A();
return B(result);
} catch(err) {
return Promise.reject(err);
}
}
someFunction().then(function(result) {
// code here to process the final result
}).catch(C);
If you also have the case where A() can return an error code, then you can do this:
function someFunction() {
try {
var result = A();
// check for error value
if (result < 0) {
throw result;
}
return B(result);
} catch(err) {
return Promise.resolve(err);
}
}
Note that both of these patterns avoid creating an extra promise if it isn't needed. They only create the extra promise when returning an error that occurred synchronously.
The Bluebird promise library has a helper function for this particular circumstance called Promise.method. The utility of Promise.method() is that it automatically wraps your function in a try/catch handler and if there are any synchronous exceptions thrown, it automatically turns them into returning a rejected promise. You could use it like this:
var someFunction = Promise.method(function() {
var result = A();
// check for error condition
if (result < 0) {
throw result;
}
return B(result);
});
someFunction().then(function(result) {
// code here to process the final result
}).catch(C);
I'm assuming that both A and B can throw errors here. Using the standard API it could look like this:
function() {
return new Promise((resolve, reject) => {
try {
resolve(A());
} catch (error) {
reject(error);
}
})
.then(B)
.catch(C);
}
This will return a promise that's either resolved with the output of B or the output of C, if that provides a fallback. You can also consider handling any errors outside of this function if that makes sense for your use case.
When using Bluebird this should also be possible:
function() {
return Promise.method(A)().then(B).catch(C)
}
I think a good way to do this would be to still use promises for the synchronous function. It keeps it consistent within a function, especially if you want something to respond to the success like a pseudo-promise. But the key is that you'd use an immediately resolved promise. Take a look at this blog post on ES6 Promises.
// an immediately resolved promise
var a = Promise.resolve(A());
assuming you've already created the promise and defined C like so:
var B = new Promise(function(resolve, reject) {
if (a) {
resolve('success'); // fulfilled successfully
}
else {
C('rejected'); // error, rejected
}
})
.then((result) => {console.log('made it!');})
.catch((result) => {C('rejected');});
var C = (err)=>{console.log('error: ' + err); return err;}
this code should do what you want:
a.then((result) => B(result));
^ this last line is the most important, since it uses the output for A to call B
i have this function in my code and I'm using throw to create meaningful errors (rather than failing silently). However, when i structure my function this way, if i call defineSandbox() with an error, it stops the whole script.
//defineSandbox is in an object, for now i name "myObj"
var defineSandbox = function (sandboxName,SandboxDefinition) {
//validation
if(!is.validString(sandboxName)) {
throw statusMessages.sandbox.invalidName;
}
if(!is.validFunction (SandboxDefinition)) {
throw statusMessages.sandbox.invalidDefinition;
}
//...some more validation here
//...sandbox builder code if validation passes (code wasn't returned)
registered.sandboxes[sandboxName] = newSandbox;
};
//intentional error, non-string name
myObj.defineSandbox(false);
//...and so the rest of the script from here down is not executed
//i can't build this sandbox anymore
myObj.defineSandbox('mySandbox',function(){...});
what i would like to have is if one call fails, it gives out an error but still tries to continue to run the script. how do i structure this code so that i can achieve that?
Typically, you don't want to continue execution when you manually throw a new error. If you want to have it for a logging purpose, you should consider an self-created internal solution.
However, to catch a thrown error you need to invoke a try / catch statement.
try {
myObj.defineSandbox(false);
} catch( ex ) {
// execution continues here when an error was thrown. You can also inspect the `ex`ception object
}
By the way, you can also specify which kind of error you want to throw, for instance a type error or a reference error like
throw new TypeError();
throw new ReferenceError();
throw new SyntaxError();
etc.
Complete list: MDN
console.error() will not throw an error, but will display an error in your log without halting execution.
If you would like to report the caught error so that window.onerror will fire, you can dispatch an error event in your catch block:
try {
}
catch (error)
{
const e = new ErrorEvent('error', {message:'my error', error:error})
window.dispatchEvent(e)
}
I found this useful for catching and reporting errors in a for loop while still continuing with the loop.
If you are trying to aggregate all the errors instead of just throwing one of them, then you should create an array of the issues (exceptions) and then throw the array, instead of just the first issue you hit.
You need to catch thrown errors if you want to deal with them nicely. In your example:
//intentional error, non-string name
try {
myObj.defineSandbox(false);
} catch(error) {
alert("Error defining sandbox: " + error);
}
And then subsequent code will still continue to run.
var bear = {};
(function () {
bear.errorProcesser = function ( e ) {
console.log( e );
}
bear.define = function ( name, fn ) {
try {
if( typeof name != "string" || typeof fn != "function"){
throw new Error ("some error");
}
bear[name] = fn;
} catch (e){
bear.errorProcesser ( e );
}
}
})()
bear.define ( "testfunc", {} );
Is it just try-catch you're searching for?