Dynamic Chaining in Javascript Promises

后端 未结 8 1296
伪装坚强ぢ
伪装坚强ぢ 2020-12-08 20:42

How can I perform dynamic chaining in Javascript Promises, all the time I have seen only hardcoding of the calls for eg., (promise).then(request/funct

相关标签:
8条回答
  • 2020-12-08 20:46

    Since promises unwrap, just continue to add then statements and it will continue to be chained together

    function asyncSeries(fns) {
      return fns.reduce(function(p, fn) {
        return p.then(fn);
      }, Promise.resolve());
    }
    

    Recursively is a pretty cool way to do it as well :)

    function countTo(n, sleepTime) {
      return _count(1);
    
      function _count(current) {
        if (current > n) {
          return Promise.resolve();
        }
    
        return new Promise(function(resolve, reject) {
          console.info(current);
          setTimeout(function() {
            resolve(_count(current + 1));
          }, sleepTime);
        });
      }
    }
    
    0 讨论(0)
  • 2020-12-08 20:51

    Given an array functions that all return promises, you can use reduce() to run them sequentially:

    var myAsyncFuncs = [
        function (val) {return Promise.resolve(val + 1);},
        function (val) {return Promise.resolve(val + 2);},
        function (val) {return Promise.resolve(val + 3);},
    ];
    
    myAsyncFuncs.reduce(function (prev, curr) {
        return prev.then(curr);
    }, Promise.resolve(1))
    .then(function (result) {
        console.log('RESULT is ' + result);  // prints "RESULT is 7"
    });
    

    The example above uses ES6 Promises but all promise libraries have similar features.

    Also, creating the array of promise returning functions is usually a good candidate for using map(). For example:

    myNewOrmModels.map(function (model) {
        return model.save.bind(model);
    }).reduce(function (prev, curr) {
        return prev.then(curr);
    }, Promise.resolve())
    .then(function (result) {
        console.log('DONE saving');
    });
    
    0 讨论(0)
  • 2020-12-08 20:52

    I think the simplest way is:

    const executePromises = function(listOfProviders){
    
        const p = Promise.resolve(null);
    
        for(let i = 0; i < listOfProviders.length; i++){
           p = p.then(v => listOfProviders[i]());
        }
    
       return p;
    
    };
    

    I believe the above is basically equivalent to:

    const executePromises = async function(listOfProviders) {
    
        for(let i = 0; i < listOfProviders.length; i++){
           await listOfProviders[i]();
        }
    
    };
    
    0 讨论(0)
  • 2020-12-08 20:57

    I just had a problem with my api provider that doing Promise.all() would end up in concurrency db problems..

    The deal with my situation is that i need to get every promise result in order to show some "all ok" or "some got error" alert.

    And i don't know why .. this little piece of code who uses reduce when the promises resolved i couldn't get my scope to work (too late to investigate now)

    $scope.processArray = function(array) {
        var results = [];
        return array.reduce(function(p, i) {
            return p.then(function() {
                return i.then(function(data) {
                    results.push(data);
                    return results;
                })
            });
        }, Promise.resolve());
    }
    

    So thanks to this post http://hellote.com/dynamic-promise-chains/ I came with this little bastard.. It's not polished but it's working all right.

    $scope.recurse = function(promises, promisesLength, results) {
    
        if (promisesLength === 1) {
            return promises[0].then(function(data){
                results.push(data);
                return results;
            });
        }
    
        return promises[promisesLength-1].then(function(data) {
            results.push(data);
            return $scope.recurse(promises, promisesLength - 1, results);
        });
    
    }
    

    Then i invoke the function like this:

    var recurseFunction = $scope.recurse(promises, promises.length, results);
    recurseFunction.then(function (response) { ... });
    

    I hope it helps.

    0 讨论(0)
  • 2020-12-08 21:03

    Check the following tutorial for

    1. programmatic (dynamic) chaining of javascript/node.js promises and
    2. Promise chaining using recursive functions

    Programmatic-Chaining-and-Recursive-Functions-with-JavaScript-Promise

    0 讨论(0)
  • 2020-12-08 21:06

    One option is to utilize the properties of objects and the ability to invoke them via strings.

    I wrote a small sample Here and posted it below.

    The idea is that you have the set of functions that you wish to run set in some namespace or object, as I did in 'myNamespace':

    myNamespace = {
        "A": function() {return "A Function";},
        "B": function() {return "B Function";},
        "C": function() {return "C Function";}
    }
    

    Then your main promise would run and somehow (via inputs, ajax, prompts, etc.) you would get the string value of the function you want to have run, which isn't known until runtime:

    My main promise uses a prompt to get a letter from the user:

    var answer = prompt('Starting.  Please pick a letter: A,B,C');
            if(myNamespace[answer] === undefined)
            {
                alert("Invalid choice!");
                reject("Invalid choice of: " + answer);
            }
            else
            {
                resolve(answer);
            }
    

    In the next 'then' I use that value (passed via the resolve function) to invoke the function:

    .then(function(response) {
            funcToRun = myNamespace[response]();})
    

    Finally, I output to html the result of my dynamic function call and I use some recursive fun to make it more interactive and demonstrate that it is dynamic:

    .then(function(){
            document.getElementById('result').innerHTML = funcToRun;})
        .then(function(){
            if(prompt("Run Again? (YES/NO)")==="YES")
            {
                doWork();
            }
        });
    

    myNamespace = {
        "A": function() {return "A Function";},
        "B": function() {return "B Function";},
        "C": function() {return "C Function";}
    }
    
    function doWork()
    {
        var funcToRun;
        
        new Promise(function(resolve,reject) {
            var answer = prompt('Starting.  Please pick a letter: A,B,C');
            if(myNamespace[answer] === undefined)
            {
                alert("Invalid choice!");
                reject("Invalid choice of: " + answer);
            }
            else
            {
                resolve(answer);
            }
        })
        .then(function(response) {
            funcToRun = myNamespace[response]();})
        .then(function(){
            document.getElementById('result').innerHTML = funcToRun;})
        .then(function(){
            if(prompt("Run Again? (YES/NO)")==="YES")
            {
                doWork();
            }
        });
    }
    
    doWork();
    <div id="result"></div>

    0 讨论(0)
提交回复
热议问题