简体   繁体   English

Javascript Promises 中的动态链接

[英]Dynamic Chaining in Javascript Promises

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/functionName).then(request/functionName)如何在 Javascript Promises 中执行动态链接,我一直只看到对调用的硬编码,例如(promise).then(request/functionName).then(request/functionName)

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 Promises but 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() . 此外,创建promise返回函数数组通常是使用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');
});

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'中所做的那样:

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> 

Since promises unwrap, just continue to add then statements and it will continue to be chained together 由于promises解包,只需继续添加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);
    });
  }
}

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 async and await for 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 promises is 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

I just had a problem with my api provider that doing Promise.all() would end up in concurrency db problems.. 我刚刚遇到api提供程序的问题,做Promise.all()会导致并发db问题。

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. 我希望它有所帮助。

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.). 如果一个函数包含一个计时器,它是行不通的(对于这个问题我也尝试jQuery的$ Callbacks,$ .Ajax和$。但它没有帮助。唯一的决定,我找到的,使用resolve()在回调一个计时器,但如果你已经完成了功能,那是不可接受的。)
  2. Testing environment 测试环境

$ google-chrome --version
Google Chrome 53.0.2785.116

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

};

To build on this answer , if you want to return the result of all those promises, too:为了建立这个答案,如果你也想返回所有这些承诺的结果:

async function chainPromises(promises) {
    let results = [];
    for (let promise of promises) { 
        let result = await promise();
        results.push(result);
    }
    return results;
}

Check the following tutorial for 请查看以下教程

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

Programmatic-Chaining-and-Recursive-Functions-with-JavaScript-Promise 编程-链接和递归函数与- JavaScript的承诺

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM