Search code examples
javascriptfunctional-programminglodashcurryingfunction-composition

Passing arguments while running lodash flow asynchronously


Given the code below, how can I pass id to the applySaveAsync function?

   var then = _.curry(function (f, thenable) {
        return thenable.then(f);
    });

    var validateAsync = _.flow(
        function () { return _(someCondition).showError(ERROR_01).value(); },  
        then(function () { return _(anotherCondition).showError(ERROR_02).value(); }) 
    );

    var save = _.flow(
        validateAsync,
        then(applySaveAsync),
        then(saveCompleted)
    );

    function applySaveAsync(id) {
        // Saving...
    }

    save(22); // Calling save function with some id.

I can get the id on the validateAsync function, but I cannot return it back since validateAsync should return a promise.

Any way to achieve that?


Solution

  • The simplest choice would be not to use _.flow for the definition of validateAsync.
    Since validateAsync does not take parameters nor has a result, you should just change the definition of save to not use _.flow:

    function save(id) {
        return validateAsync()
        .then(function(){ return applySaveAsync(id) })
        .then(saveCompleted)
    }
    

    We could also change validateAsync to pass through the id:

    function validateAsync(id) {
        return _(someCondition).showError(ERROR_01).value()  
        .then(function () { return _(anotherCondition).showError(ERROR_02).value(); })
        .then(_.constant(id));
    }
    

    and even do that while still using _.flow

    var validateAsync = _.flow(
        function(id) { return _(someCondition).showError(ERROR_01).value().then(_.constant(id)); },  
        then(function(id) { return _(anotherCondition).showError(ERROR_02).value().then(_.constant(id)); }) 
    );
    

    but I would advise against that since validateAsync is not supposed to be a function that does takes parameters.

    Let's write a wrapper function for such instead to let us do the pass-around in a functional way:

    function pass(fn) {
        return function(id) {
            return fn().then(function() {
                return id;
            });
        }
    }
    

    (if you prefer, you can try to compose that from then, _.constant and more)
    so that one can write

    var save = _.flow(
        wrap(validateAsync),
        then(applySaveAsync),
        then(saveCompleted)
    );