繁体   English   中英

同步循环中的Javascript许诺

[英]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.

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