簡體   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