0

I have the following example:

function foo1 (callback) {

    if (!foo2(callback)) {
        return;
    }

    console.log("Doing something");
    /* do something */
}

function foo2 (callback) {
    return callback ();
}

foo1 (function () {
     console.log ("Hello World!");
});

I want to remove the if from foo1. Can I stop foo1 execution calling foo2? I am looking for something like this:

function foo1 (callback) {

    foo2(callback); // calling foo2 this way I want to prevent
                    // the console.log below to be executed

    console.log("Doing something");
    /* do something */
}

Is there any way to do this?

Note that I don't want to throw an error. I just want to call the callback function and to stop the function execution.

Use case

Instead of this:

 function a (options, callback) {

     callback = callback || function () {};
     if (typeof callback !== "function") {
         callback = function (err) { console.log (err); }
     }

     if (!options.someField || options.someField.constructor !==  Object) {
         return callback ("someField should be an object");
     }

     /* do something */
 }

I want to have:

 function a (options, callback) {

     validateFunction (callback, callback);
     validateObject (options, callback);
     validateObject (options.somField, callback);

     /* do something */
 }

If one of the validate* functions fails it should send the error via callback and stop a function execution.

6
  • very weird, post a real example... Commented Apr 3, 2014 at 8:12
  • @GabrielLlamas Hope it's clear now. Commented Apr 3, 2014 at 8:16
  • What do you think is the problem with using if statement? Commented Apr 3, 2014 at 10:35
  • @Esailija The same code appears in all functions when I validate the fields. Commented Apr 3, 2014 at 10:37
  • I think all your problems would disappear with promises Commented Apr 3, 2014 at 10:39

4 Answers 4

1

If you can use promises:

 function a (options) {
     return validateObject(options).then(function(){
         return validateObjecT(options.somField);
     }).then(function(){
          return validateObjecT2(options.somField);
     }).then(function(){
          return validateObjecT3(options.somField);
     }).then(function(){
          return validateObjecT4(options.somField);
     }).then(function(){
          /*do something*/
     });
 }

 var validateObject = Promise.method(function(object) {
      // Because this is inside Promise.method, thrown error
      // will be equal to return Promise.reject(new Error("invalid"));
      if (typeof object !== "object") throw new Error("invalid");
 });

Alternatively function a can be also done like this:

function a (options) {
 // If any validation fails, the do something is skipped
 // and the code resumes at the next .catch() with the validation
 // error passed as parameter
 return Promise.all([
    validateObject(options),
    validateObject2(options),
    validateObject3(options),
    validateObject4(options),
    validateObject(options)
 ]).then(function(){
    /*do something*/
 })
}

 a({}).then(function() {
    // Validation succeeded and everything was done
 }).catch(function(e) {
    // Validation or something else failed, e is the rejection error
 });

Btw don't use strings as errors, a string is not an error.

That is, never do:

throw "foo";
callback("foo");
reject("foo") // When using promises

Instead do:

throw new Error("foo");
callback(new Error("foo"));
reject(new Error("foo")) // When using promises
Sign up to request clarification or add additional context in comments.

9 Comments

+1, looks good. But the issue is: can I put /* do something */ code out of the then callback? It would be very easy to provide a callback function to validateObject function.
@IonicăBizău no but there is no benefit of having the code outside then, it will still be flat even if it's inside then.
Just to avoid entering in the callback hell. I try to prevent indentation if that's possible.
@IonicăBizău the code will be flat even if code is inside then i.e. no callback hell
Please post an example with 4 validations.
|
1

There is a way, use throw

function foo2(callback) {
    // do what you want to do
    throw true;
}

And then catching it

try {
   foo1();
}
catch (e) {
   // if false, real error, 
}

But it appears at a strange design. I hope that you have a valid reason and that it's clear to others whom is reviewing your code in the future.

Comments

1

I would use if statements:

function a (options, callback) {

    if (!validateFunction (callback)) return;
    if (!validateObject (options, callback)) return;
    if (!validateObject (options.somField, callback)) return;

    /* do something */
}

where the validateFunction function does not necessarily need 2 parameters if you call it always from such a scenario and the validate... functions always return a boolean with the result of the validation AND calling the callback in case of error.

function validateObject (options, errorCallback) {

    if (!options.someField || options.someField.constructor !==  Object) {
        errorCallback("someField should be an object");
        return false;
    }

    return true;
}

As many purists say, building an execution flow using try catch is not the right thing to do. There is also the performance issue. Using try catch is less performant then the control statements (e.g. if)

And there is though a try catch version that is faster and produces less code but I still don't prefer it because it is less clear in the code:

function a (options, callback) {

    try {
        validateFunction (callback);
        validateObject (options);
        validateObject (options.someField);
    catch (err) {
        callback(err);
        return;
    }

    /* do something */
}

function validateObject (options, errorCallback) {
    if (!options.someField || options.someField.constructor !==  Object) {
        throw "someField should be an object";
    }
}

Comments

0

take a boolean for your function

function foo1(callback, exe) {

    if (exe) {
        foo2(callback);
    } else {
        console.log("Doing something");
        /* do something */
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.