[英]Javascript promise in synchronous loop
我的任务很简单,但这使我不敢理hair。 已经搜索了整个Internet,找到的解决方案都无法直接翻译成我的问题。 这是JavaScript的后续问题-无法返回
这是我得到的:
var worksheetArray;
var filtersArray =[];
function testu(){
filtersArrayFetch();
console.log("finished fetching");
console.log(filtersArray);
//do more stuff with array
}
function filtersArrayFetch()
{
workbook = viz.getWorkbook();
sheet=viz.getWorkbook().getActiveSheet();
worksheetArray = sheet.getWorksheets();
for (var i=0; i<worksheetArray.length; i++) {
(function(num){
worksheetArray[i].getFiltersAsync()
.then(function(promise){
for (j=0;j<promise.length;j++)
{
filtersArray.push(promise[j].getFieldName());
}
})
})(i);
}
console.log("after for");
}
用简单的英语来说-我有一个用同步Tableau API函数提取的工作表数组。 getFiltersAsync()
返回Promise作为数组。 在此数组上,我想执行getFieldName
并将其推到最终的数组中,稍后我将在代码中使用它。 代码工作,直到worksheetArray[i].getFiltersAsync()
但不计算.then()
并返回undefined来testu()
函数。 单击按钮调用testu()
。 我需要保持IE(Edge)兼容性,因此Promise.all()不是一个选择。
脚本有什么问题? 为什么不评估.then()
?
编辑:
我设法使用自动调用的运行器功能解决了这个问题:
function filtersearch2(i){
workbook = viz.getWorkbook();
sheet=viz.getWorkbook().getActiveSheet();
worksheetArray = sheet.getWorksheets();
var filtersArray=[];
var d=$.Deferred();
(function runner(i){
worksheetArray[i].getFiltersAsync().then(
function(filtersArrayReturnedInPromise){
for (z=0;z<filtersArrayReturnedInPromise.length;z++){
field = filtersArrayReturnedInPromise[z].getFieldName();
if (field.search("AutoFilter")>0 && field.search("Action")==-1 ){
filtersArray[filtersArray.length]=field;
}
}
if (i==worksheetArray.length-1){
var uniq = filtersArray.reduce(function(a,b){
if (a.indexOf(b) < 0 ) a.push(b);
return a;
},[]);
console.log("resolving filtersearch");
d.resolve(uniq);
} else {
i++;
runner(i);
}
});
})(i)
return d.promise();
}
请使用/声明(本地)变量,并停止污染全局名称空间。
我已经重写了您的代码以正确履行承诺。
filtersArrayFetch()
必须返回一个promise,以便其他函数可以处理其计算结果。 并且testu()
需要使用此promise来确定何时完成filtersArrayFetch
。
您的代码在尝试处理/记录filtersArray
之前没有等待承诺解决。 而且,使用在filtersArray
中修改的全局/共享filtersArray
方法本身非常危险/无法预测。 将该模式带到您调用两次的函数,所有地狱都会崩溃。 您不仅会扯掉头发,还会在尝试重现某些结果或调试可能造成的混乱时激怒您。
因为当一些随机承诺完成并开始向该数组添加项目时,大多数代码都不知道。 也不叫这些项目来自什么函数。
function testu(){
filtersArrayFetch().then(filtersArray => {
console.log("finished fetching");
console.log(filtersArray);
//do more stuff with array
});
}
function filtersArrayFetch() {
//a few functions that define some tasks/steps that need to be done
//in order to do the whole task.
//Array<Array<*>> -> Array<*>
var flatten = arrays => [].concat(...arrays);
//filter -> fieldName
var getFieldName = filter => filter.getFieldName();
//Array<filter> -> Array<fieldName>
var filtersToFieldNames = filters => filters.map(getFieldName);
//worksheet -> Promise<Array<fieldName>>
var worksheetToFieldNames = worksheet => worksheet.getFiltersAsync().then(filtersToFieldNames);
//telling by your code, to this point everything should be sync.
var worksheets = viz.getWorkbook().getActiveSheet().getWorksheets();
return Promise.all(worksheets.map(worksheetToFieldNames)).then(flatten);
}
worksheets.map(worksheetToFieldNames)
将Array<worksheet>
转换为Array<Promise<Array<fieldName>>>
。 通过Promise.all()
运行此Promise.all()
后,我们得到一个Promise<Array<Array<fieldName>>>
。 数组的承诺; 对于每个工作表,一个字段名数组。
在运行.then(flatten)
我们有了一个普通的Promise<Array<fieldName>>
。
但是从我们开始处理承诺的那一刻起,我们将不得不继续处理承诺。 我们无法解开值并获得同步。 因此,此函数可以返回的唯一内容是Promise (无论如何) 。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.