如何在Javascript Promises中执行动态链接,我一直只看到调用的硬编码,例如。(promise).then(request/functionName).then(request/functionName)
答案 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;
答案 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));
您可以将async
和await
用于此目的。
async function chainPromises(promises) {
for (let promise of promises) { // must be for (.. of ..)
await promise();
}
}
这将按顺序(逐个)执行给定的功能,而不是并行执行。参数promises
是一个函数数组,返回Promise
。
答案 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
注意:
$ 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)
查看以下教程
Programmatic-Chaining-and-Recursive-Functions-with-JavaScript-Promise