Javascript承诺中的动态链接

时间:2015-06-15 19:17:17

标签: javascript promise

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

8 个答案:

答案 0 :(得分:41)

给定一个都返回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"
});

上面的示例使用ES6 Promises,但所有promise库都具有相似的功能。

此外,创建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');
});

答案 1 :(得分:7)

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

我写了一个小样本Here并将其发布在下面。

我们的想法是,您可以在某个命名空间或对象中设置要运行的一组函数,就像我在“myNamespace'”中所做的那样:

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

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

我的主要承诺是使用提示来获取用户的来信:

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

在下一个'然后'我使用该值(通过resolve函数传递)来调用函数:

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

最后,我将动态函数调用的结果输出到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>
&#13;
&#13;
&#13;

答案 2 :(得分:4)

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

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

递归是一种非常酷的方式:)

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

答案 3 :(得分:1)

这是ES7方式。

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

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

你想这样打电话。

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

您可以将asyncawait用于此目的。

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

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

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

答案 4 :(得分:0)

此解决方案基于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

<强>代码

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

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

注意:

  1. 如果函数包含计时器,则不起作用(针对此问题) 我也尝试jQuery的$ Callbacks,$ .Ajax和$ .When但它没有帮助。 唯一的决定,我发现,在回调中使用resolve() 计时器,但如果您已完成功能,则无法接受。)。
  2. 测试环境
  3. $ google-chrome --version
    Google Chrome 53.0.2785.116
    

答案 5 :(得分:0)

我的api提供程序遇到了一个问题,即Promise.all()最终会出现并发db问题。

处理我的情况是我需要获得每一个承诺结果,以便显示一些“一切正常”或“一些错误”警告。

我不知道为什么......当承诺解决时,使用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());
}

所以感谢这篇文章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);
    });

}

然后我调用这样的函数:

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

我希望它有所帮助。

答案 6 :(得分:0)

我认为最简单的方法是:

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;

};

我相信以上内容基本上等同于:

const executePromises = async function(listOfProviders) {

    for(let i = 0; i < listOfProviders.length; i++){
       await listOfProviders[i]();
    }

};

答案 7 :(得分:-1)

查看以下教程

  1. javascript / node.js promises和
  2. 的程序化(动态)链接
  3. 使用递归函数保证链接
  4. Programmatic-Chaining-and-Recursive-Functions-with-JavaScript-Promise