Search code examples
javascriptes6-promisecallstack

What is the best solution to attaching a then onto a promise multi-level down the call stack?


Consider such a senario:

function func_topmost(){
    ...
    func_layer1();
    pseudo_code for some actions here; // an action that needs to run AFTER the promise in func_layer2 fulfilled.
}

function func_layer1(){
    ...
    func_layer2();
}

function func_layer2(){
    var the_vital_promise = $.post('very_slow_backend_response', data);
    return the_vital_promise;
}

The above is just an illustration. In reality the call stack could be even deeper and there is always a possibility that another layer of function will be introduced to the call stacks in future development.

My question is, what is the best practice to make sure that the actions in the topmost layer function that dependent on the fulfillment of the promise in the bottom layer attached properly?

Right now I can think of making all the functions in the calling chain async function all the way to the bottom. I am not sure if this is the right solution, and it makes later maintenance very rigid.


Solution

  • So you have multiple normal functions calling each other, and all of a sudden the one on top of a stack happens to handle some asynchronous task and you are looking for a way to solve the issue with minimum code change. There are 3 ways that I am aware of to handle that and 2 of them are already mentioned, but I think they have some drawbacks.

    1. Returning a promise

    • Will break the code structure
    • Requires change in all functions

    2. Async/await

    async function func_topmost(){
        const data = await func_layer1();
        pseudo_code for some actions here; // an action that needs to run AFTER the promise in func_layer2 fulfilled.
    }
    
    function func_layer1(){
        const promise = func_layer2();
        return promise;
    }
    
    function func_layer2(){
        var the_vital_promise = $.post('very_slow_backend_response', data);
        return the_vital_promise;
    }
    
    • less code change than returning a promise but more code in compiled bundle
    • Requires change in all functions

    3. Dispatch an event

    This seems to be the best way of handling the problem to me if you have many functions stacked. You can use events library if you are on Node, or custom DOM events if the environment is the browser. This way you only need to change the first and the last function (if the functions in between doesn't depend on promise completion) and the code structure is kept.

    function func_layer2(){
        var the_vital_promise = $.post('very_slow_backend_response', data)
        .then(res => {
             events.emit('customEvent');
         });
        return the_vital_promise;
    }
    
    function func_topmost(){
        ...
        events.on('customEvent', () => {
             pseudo_code for some actions here; // an action that needs to run AFTER the promise in func_layer2 fulfilled.
        });
        func_layer1();
    }