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