Javascript Promise 中的动态链接

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/30853265/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-28 12:48:15  来源:igfitidea点击:

Dynamic Chaining in Javascript Promises

javascriptpromise

提问by Ramu Ajay

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

我怎样才能在 Javascript Promises 中执行动态链接,我一直只看到对例如调用的硬编码,(promise).then(request/functionName).then(request/functionName)

采纳答案by JasonWilczak

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

一种选择是利用对象的属性以及通过字符串调用它们的能力。

I wrote a small sample Hereand 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”中所做的那样:

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:

然后你的主要承诺会运行,并且以某种方式(通过输入、ajax、提示等)你会得到你想要运行的函数的字符串值,直到运行时才知道:

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' 中,我使用该值(通过 resolve 函数传递)来调用该函数:

.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:

最后,我将动态函数调用的结果输出到 html,并使用一些递归乐趣来使其更具交互性并证明它是动态的:

.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>

回答by wuher

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

给定一个都返回 promise 的数组函数,您可以使用reduce()它们按顺序运行:

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 Promisesbut all promise libraries have similar features.

上面的例子使用ES6 Promises,但所有的Promise库都有相似的特性。

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

此外,创建 promise 返回函数的数组通常是使用map(). 例如:

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');
});

回答by Travis Kaufman

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

由于promise解包,只需继续添加then语句,它将继续链接在一起

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);
    });
  }
}

回答by allenhwkim

This is ES7 way.

这是 ES7 的方式。

Let's say you have multiple promises defined in an array.

假设您在一个数组中定义了多个 Promise。

  var funcs = [
    _ => new Promise(res => setTimeout(_ => res("1"), 1000)),
    _ => new Promise(res => setTimeout(_ => res("2"), 1000))
  }

And you want to call like this.

你想这样打电话。

 chainPromises(funcs).then(result => console.log(result));

You can use asyncand awaitfor this purpose.

您可以使用asyncawait用于此目的。

  async function chainPromises(promises) {
    for (let promise of promises) {  // must be for (.. of ..)
      await promise();
    }
  }

This will execute the given functions sequentially(one by one), not in parallel. The parameter promisesis an array of functions, which return Promise.

这将按顺序(一个接一个)执行给定的函数,而不是并行执行。参数promises是一个函数数组,它返回Promise.

Plunker: http://plnkr.co/edit/UP0rhD?p=preview

Plunker:http://plnkr.co/edit/UP0rhD?p=preview

回答by Daniel S.

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

我的 api 提供者只是遇到了一个问题,即执行 Promise.all() 最终会导致并发数据库问题..

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)

而且我不知道为什么..当承诺解决时使用reduce的一小段代码我无法让我的范围工作(现在调查太晚了)

$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.

所以多亏了这篇文章http://hellote.com/dynamic-promise-chains/我带着这个小混蛋来了..它没有打磨但工作正常。

$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.

我希望它有帮助。

回答by Alexander Mills

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]();
    }

};

回答by PADYMKO

This solution based on usage promises of introduced in the EcmaScript 6 (https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise), so before use it see table browser`s support https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise#Browser_compatibility

此解决方案基于 EcmaScript 6 ( https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise)中引入的使用承诺,因此在使用之前请参阅表格浏览器的支持https: //developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise#Browser_compatibility

Code

代码

var f1 = function(){
    for (var i = 0; i < 800000000; i++) {}
    console.log('Function1 is done');
}
var f2 = function(){
    for (var i = 0; i < 800000000; i++) {}
    console.log('Function2 is done');
}
var f3 = function(){
    for (var i = 0; i < 800000000; i++) {}
    console.log('Function3 is done');
}
var f4 = function(){
    for (var i = 0; i < 800000000; i++) {}
    console.log('Function4 is done');
}


callbacks = function(){

    // copy passed arguments
    var callbacks = arguments;

    // create array functions
    var callbacks = Object.keys(callbacks).map(function(el){ return callbacks[el] });

    var now = Date.now();

    callbacks.reduce(function(previousPromise, currentFunc){
        return previousPromise.then(
            function(){
                currentFunc();
                var seconds = (Date.now() - now) / 1000;
                console.log('Gone', seconds, 'seconds');
            }
        )
    }, Promise.resolve());
}

callbacks(f1, f2, f3, f4);

Result in Chrome console (values seconds will be different):

结果在 Chrome 控制台(值秒会有所不同):

Function1 is done
Gone 1.147 seconds
Function2 is done
Gone 2.249 seconds
Function3 is done
Gone 3.35 seconds
Function4 is done
Gone 4.47 seconds

Notes:

笔记:

  1. It is does not work if a function contains a timer (for this problem I try also jQuery`s $Callbacks, $.Ajax and $.When but it not help. The only decision, what I found, usage resolve() in callback of a timer, but it is not acceptable if you have completed functions.).
  2. Testing environment
  1. 如果一个函数包含一个计时器,它就不起作用(对于这个问题,我也尝试了 jQuery 的 $Callbacks、$.Ajax 和 $.When 但它没有帮助。我发现的唯一决定是在回调中使用 resolve()一个计时器,但如果你已经完成了功能,它是不可接受的。)。
  2. 测试环境


$ google-chrome --version
Google Chrome 53.0.2785.116

回答by Tuhin Paul

Check the following tutorial for

检查以下教程

  1. programmatic (dynamic) chaining of javascript/node.js promises and
  2. Promise chaining using recursive functions
  1. javascript/node.js 承诺的程序化(动态)链接和
  2. 使用递归函数的 Promise 链接

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

带有 JavaScript Promise 的编程链和递归函数