简体   繁体   English

同步循环中的Javascript许诺

[英]Javascript promise in synchronous loop

I have fairly simple task but it makes me pull my hair out. 我的任务很简单,但这使我不敢理hair。 Already searched whole Internet and none of the solutions found can be directly translated to my problem. 已经搜索了整个Internet,找到的解决方案都无法直接翻译成我的问题。 It's a follow up question to JavaScript - no return 这是JavaScript的后续问题-无法返回

Here's what I got: 这是我得到的:

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

}

In plain English -I have an array of worksheets fetched with synchronous Tableau API function. 用简单的英语来说-我有一个用同步Tableau API函数提取的工作表数组。 getFiltersAsync() returns Promise as an Array. getFiltersAsync()返回Promise作为数组。 On this Array I would like to perform getFieldName and push it to final Array I will be using later in the code. 在此数组上,我想执行getFieldName并将其推到最终的数组中,稍后我将在代码中使用它。 Code works until worksheetArray[i].getFiltersAsync() but does not evaluate .then() and returns undefined to testu() function. 代码工作,直到worksheetArray[i].getFiltersAsync()但不计算.then()并返回undefined来testu()函数。 testu() is being called by button click. 单击按钮调用testu() I need to keep IE(Edge) compatibility so Promise.all() is not an option. 我需要保持IE(Edge)兼容性,因此Promise.all()不是一个选择。

What is wrong with the script? 脚本有什么问题? Why it's not evaluating .then() ? 为什么不评估.then()

EDIT: 编辑:

I've managed to solve the problem using self-invoking runner function: 我设法使用自动调用的运行器功能解决了这个问题:

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

please use/declare (local) variables and stop polluting the global namespace. 请使用/声明(本地)变量,并停止污染全局名称空间。

I've rewritten your code to properly deal with the promises. 我已经重写了您的代码以正确履行承诺。

filtersArrayFetch() has to return a promise so that other functions can deal with the result of its computation. filtersArrayFetch()必须返回一个promise,以便其他函数可以处理其计算结果。 And testu() needs to use this promise in order to determine when filtersArrayFetch is done. 并且testu()需要使用此promise来确定何时完成filtersArrayFetch

Your code didn't wait for the promises to resolve, before trying to process/log the filtersArray . 您的代码在尝试处理/记录filtersArray之前没有等待承诺解决。 And your approach with the global/shared filtersArray that is modified in the promises is pretty dangerous/unpredictable itself. 而且,使用在filtersArray中修改的全局/共享filtersArray方法本身非常危险/无法预测。 Take that pattern to a function that you call twice and all hell will break loose; 将该模式带到您调用两次的函数,所有地狱都会崩溃。 you'll not only rip out your hair, it'll set your head on fire when trying to reproduce some result or debugging the mess that this can create. 您不仅会扯掉头发,还会在尝试重现某些结果或调试可能造成的混乱时激怒您。
Because most of your code will have no clue when some random promise will finish and start adding items to that array; 因为当一些随机承诺完成并开始向该数组添加项目时,大多数代码都不知道。 nor what function call these items are coming from. 也不叫这些项目来自什么函数。

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) transforms an Array<worksheet> into an Array<Promise<Array<fieldName>>> . worksheets.map(worksheetToFieldNames)Array<worksheet>转换为Array<Promise<Array<fieldName>>> After running this through Promise.all() we have a Promise<Array<Array<fieldName>>> . 通过Promise.all()运行此Promise.all()后,我们得到一个Promise<Array<Array<fieldName>>> The promise of an Array of Arrays; 数组的承诺; for each worksheet an array of fieldnames. 对于每个工作表,一个字段名数组。

And after running this through .then(flatten) we have a plain Promise<Array<fieldName>> . 在运行.then(flatten)我们有了一个普通的Promise<Array<fieldName>>

But from the point we started to deal with promises we will have to continue dealing with promises. 但是从我们开始处理承诺的那一刻起,我们将不得不继续处理承诺。 We cannot unwrap the values and get sync anymore. 我们无法解开值并获得同步。 So the very only thing this function can return is a Promise (of whatever) . 因此,此函数可以返回的唯一内容是Promise (无论如何)

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

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