2015-11-04 69 views
0

以下腳本按預期方式運行,當外部循環迭代小於約。 100次。如果外層循環重複數千次,我可以看到我的console.log被混淆了。例如:JavaScript async/await和do/while循環

  • 3倍外環輸出
  • 1X內環輸出
  • 1個外環輸出//應該不會發生,因爲所有外環 輸出是內環路輸出之前!

......或者......

  • 3倍外環輸出
  • 2X內環輸出//不應該發生,因爲只有一個內 環路輸出!

......還有很多其他奇怪的組合,但我認爲它總是同樣的原因。

似乎async/await和do/while循環的組合在我的情況下不能正常工作。我試圖通過製作單獨的遞歸函數來擺脫do/while循環,但徒勞無益。有沒有另外一種方法呢?任何幫助非常感謝。

async function asyncGenerator() { 
    // other code 
    do { 
    // other code 
    var fileList = await listFiles(nextPageToken); 
    // other code 
    do { 
     // other code 
     var parents = await requestParents(fileList.result.items[0].parents[0].id); 
     // other code 
    } while (response.result.parents[0].isRoot === false); 
    // other code 
    } while (fileList.result.nextPageToken !== "undefined") 
    // other code 
} 

function listFiles(token) { 
    return gapi.client.drive.files.list({ 
    'maxResults': sizeResults, 
    'pageToken': token, 
    'q': query 
    }); 
} 

function requestParents(fileId) { 
    return gapi.client.drive.files.get({ 
    'fileId': fileId 
    }); 
} 

編輯:

  • 按照要求,請找原代碼的下方。
  • 我認爲你需要創建一個新的谷歌開發者控制檯項目 並插入相應的「clientId」和「apiKey」。
  • 我在此期間用遞歸的 函數調用交換了外部do/while循環,但輸出仍然很奇怪。
  • 我不確定如何包含browser.js和runtime.js, ,因此script-tags仍包含我的路徑。
  • 此外,我不確定,如果這是在第四個腳本標記中的片段中工作: type =「text/babel」src =「js/driverights.js」。

"use strict"; 
 

 
var driveRights = (function() { 
 
    var clientId = 'YOUR CLIENT ID'; 
 
    var apiKey = 'YOUR API KEY'; 
 
    var scopes = 'https://www.googleapis.com/auth/drive https://www.googleapis.com/auth/drive.readonly https://www.googleapis.com/auth/drive.appfolder https://www.googleapis.com/auth/drive.apps.readonly https://www.googleapis.com/auth/drive.file https://www.googleapis.com/auth/drive.install https://www.googleapis.com/auth/drive.metadata https://www.googleapis.com/auth/drive.metadata.readonly https://www.googleapis.com/auth/drive.photos.readonly https://www.googleapis.com/auth/drive.scripts'; 
 

 
    function handleClientLoad() { 
 
    var initButton = document.getElementById('init'); 
 
    initButton.onclick = function() { 
 
     gapi.client.setApiKey(apiKey); 
 
     window.setTimeout(checkAuth(false, handleAuthResult), 1); 
 
    } 
 
    } 
 

 
    function checkAuth(imm, callback) { 
 
    gapi.auth.authorize({ 
 
     client_id: clientId, 
 
     scope: scopes, 
 
     immediate: imm 
 
    }, callback); 
 
    } 
 

 
    function handleAuthResult(authResult) { 
 
    if (authResult) { 
 
     gapi.client.load('drive', 'v2', initialize); 
 
    } else { 
 
     $('#progress').html('Anmeldung fehlgeschlagen'); 
 
    } 
 
    } 
 

 
    ///////////////////////////////////////////////////////////////////////////////////////////////////// 
 

 
    var timeOut = 120; 
 
    var counter = 0; 
 
    var tokenMemory; 
 
    var start = new Date().getTime(); 
 
    var currentTime; 
 
    // Test data 
 
    var sizeResults = 1; 
 
    var parentFolders = ['0B11RmPttIhB3aFhaMzFQQ0Rjbm8', '0B6R9YDOGf_BUSC0wNW1lRWlnSmc', '0B6R9YDOGf_BUUHRoUW9tRkljUFk', '0B6R9YDOGf_BUfjc3QlZ1YU9Tb2lHcmhLVGhWc3FqSzE4S1dvZlhlLWd6aVFhUWdENWkyYkU']; 
 
    var newUser = '[email protected]'; 
 
    var query = 'trashed = false'; 
 

 
    var initialize = function() { 
 
    $('#start').click(function() { 
 
     asyncGenerator(); 
 
    }); 
 
    }; 
 

 
    async function asyncGenerator(token) { 
 
    try { 
 
     // REQUEST FILES 
 
     counter += sizeResults; 
 
     tokenMemory = token; 
 
     await sleep(timeOut); 
 
     var fileList = await listFiles(token); 
 
     console.log("Requested so far: ", counter); 
 
     console.log("Number of received files: ", fileList.result.items.length); 
 
     console.log(fileList); 
 

 
     // END REACHED 
 
     if (fileList.result.items.length === 0) { 
 
      console.log("DONE - no more files"); 
 
      return; 
 
     } 
 

 
     // CHECK FILES 
 
     var firstCheckResult = firstCheck(fileList.result.items[0]); 
 
     // Rights 
 
     if (firstCheckResult === "rights") { 
 
      $('#progress').append(`Rechte | ${fileList.result.items[0].title} | ${fileList.result.items[0].owners[0].displayName} | ${fileList.result.items[0].alternateLink} <br>`); 
 
      console.log("TO DO: rights"); 
 
     } 
 
     // Check parents 
 
     if (firstCheckResult === "checkParents") { 
 
      var parentID = fileList.result.items[0].parents[0].id; 
 
      do { 
 
      console.log("Do while loop parents are not root"); 
 
      await sleep(timeOut); 
 
      var response = await requestParents(parentID); 
 
      parentID = response.result.parents[0].id; 
 
      } while (response.result.parents[0].isRoot === false); 
 
      var secondCheckResult = secondCheck(response); 
 
     } 
 
     // No change 
 
     if (firstCheckResult === "notChange" || secondCheckResult === "notChange") { 
 
      console.log("TO DO: not"); 
 
     } 
 
     // Change 
 
     if (firstCheckResult === "change" || secondCheckResult === "change") { 
 
      console.log("TO DO: change"); 
 
      await sleep(timeOut); 
 
      await requestPermissions(fileList.result.items[0].id); 
 
     } 
 

 
     // REFRESH TOKEN IF NECESSARY 
 
     currentTime = new Date().getTime(); 
 
     if (currentTime > (start + 2700000)) { 
 
      start = new Date().getTime(); 
 
      console.log("Restart asyncGenerator! Reason: Create new token"); 
 
      checkAuth(true, asyncGenerator); 
 
     } 
 

 
     // CHECK IF NEXT PAGE TOKEN EXISTS 
 
     if (typeof fileList.result.nextPageToken !== "undefined") { 
 
      asyncGenerator(fileList.result.nextPageToken); 
 
     } else { 
 
      console.log("DONE - no next page token"); 
 
     } 
 

 
    // RESTART IF ERROR OCCURS 
 
    } catch (err) { 
 
     console.log(err); 
 
     if (err.result.error.code === 500) { 
 
     console.log("Restart asyncGenerator! Reason: Error 500"); 
 
     asyncGenerator(tokenMemory); 
 
     } 
 
     if (err.result.error.message.indexOf("Es ist ein interner Fehler aufgetreten, der die Freigabe") > -1) { 
 
     console.log("Restart asyncGenerator! Reason: Permission Error"); 
 
     asyncGenerator(tokenMemory); 
 
     } 
 
    } 
 
    } 
 

 
    function listFiles(token) { 
 
    return gapi.client.drive.files.list({ 
 
     'maxResults': sizeResults, 
 
     'pageToken': token, 
 
     'q': query 
 
    }); 
 
    } 
 

 
    function requestParents(fileId) { 
 
    return gapi.client.drive.files.get({ 
 
     'fileId': fileId 
 
    }); 
 
    } 
 

 
    function requestPermissions(fileId) { 
 
    return gapi.client.drive.permissions.insert({ 
 
     'fileId': fileId, 
 
     'sendNotificationEmails': false, 
 
     'resource': { 
 
     'value': newUser, 
 
     'type': 'user', 
 
     'role': 'writer', 
 
     'name': 'Team' 
 
     } 
 
    }); 
 
    } 
 

 
    function firstCheck(file) { 
 
    // File can't be shared -> output to site 
 
    if (file.writersCanShare === false) { 
 
     return "rights"; 
 
    } 
 
    // File is forbidden folder -> do not change 
 
    else if (parentFolders.indexOf(file.id) > -1) { 
 
     return "notChange"; 
 
    } 
 
    // File is root-folder and has no parents -> do change 
 
    else if (file.parents.length === 0 && parentFolders.indexOf(file.id) === -1) { 
 
     return "change"; 
 
    } 
 
    // Parent-folder of file is root-folder and parent-folder ist not a forbidden folder -> do change 
 
    else if (file.parents[0].isRoot === true && parentFolders.indexOf(file.parents[0].id) === -1) { 
 
     return "change"; 
 
    } 
 
    // Parent-folder of file is a forbidden-folder -> do not change 
 
    else if (parentFolders.indexOf(file.parents[0].id) > -1) { 
 
     return "notChange"; 
 
    } 
 
    // If none of these exceptions is met -> check parent 
 
    else { 
 
     return "checkParents"; 
 
    } 
 
    } 
 

 
    function secondCheck(file) { 
 
    // If file's parent is one of the forbidden folders-> do not change 
 
    if (parentFolders.indexOf(file.result.id) > -1) { 
 
     return "notChange"; 
 
    } else { 
 
     return "change"; 
 
    } 
 
    } 
 

 
    function sleep(ms) { 
 
    return new Promise(resolve => setTimeout(resolve, ms)); 
 
    } 
 

 
    return { 
 
    start: handleClientLoad, 
 
    }; 
 
})(); 
 

 
driveRights.start();
.cover { 
 
\t margin: 5% 0; 
 
\t background: none; 
 
} 
 

 
.full { 
 
    background: url(cover.jpg) no-repeat center center fixed; 
 
    -webkit-background-size: cover; 
 
    -moz-background-size: cover; 
 
    -o-background-size: cover; 
 
    background-size: cover; 
 
} 
 

 
.coverbox { 
 
    background-color: rgba(255,255,255,0.8) !important; 
 
} 
 

 
.separator { 
 
    border: 0; 
 
    height: 1px; 
 
    background-image: -webkit-linear-gradient(left, rgba(0,0,0,0), rgba(0,0,0,0.75), rgba(0,0,0,0)); 
 
    background-image: -moz-linear-gradient(left, rgba(0,0,0,0), rgba(0,0,0,0.75), rgba(0,0,0,0)); 
 
    background-image:  -ms-linear-gradient(left, rgba(0,0,0,0), rgba(0,0,0,0.75), rgba(0,0,0,0)); 
 
    background-image:  -o-linear-gradient(left, rgba(0,0,0,0), rgba(0,0,0,0.75), rgba(0,0,0,0)); 
 
} 
 

 
#init, #start { 
 
\t width: 200px; 
 
\t margin-top: 10px; 
 
}
<!DOCTYPE> 
 
<html> 
 

 
<head> 
 
\t <title>Drive Rights</title> 
 
\t <link rel="stylesheet" href="style.css"> 
 
\t <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css"> 
 

 
\t <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script> 
 
\t <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.min.js"></script> 
 
    
 
\t <script type="text/javascript" src="js/browser.js"></script> 
 
\t <script type="text/babel" src="js/driverights.js"></script> 
 
\t <script type="text/javascript" src="js/runtime.js"></script> 
 
\t <script src="https://apis.google.com/js/client.js"></script> 
 
</head> 
 

 
<body class="cover full"> 
 
\t <div class="container"> 
 
\t \t <div class="jumbotron coverbox clearfix"> 
 
\t \t \t <h1>Drive Rights</h1> 
 
\t \t \t <p> 
 
\t \t \t \t Change file permissions for specific user. 
 
\t \t \t </p> 
 
\t \t \t <hr class="separator"> 
 
\t \t \t <div id="info" class="clearfix"> 
 
\t \t \t \t <p> 
 
\t \t \t \t \t First click login, then start. 
 
\t \t \t \t </p> 
 
\t \t \t \t <p class="text-center"> 
 
\t \t \t \t \t <button type="button" class="btn btn-primary btn-lg" id="init"> 
 
\t \t \t \t \t \t Login 
 
\t \t \t \t \t </button></br> 
 
\t \t \t \t \t <button type="button" class="btn btn-primary btn-lg" id="start"> 
 
\t \t \t \t \t \t Start 
 
\t \t \t \t \t </button> 
 
\t \t \t \t </p> 
 
\t \t \t </div> 
 
\t \t \t <div id="progress"></div> 
 
\t \t </div> 
 
</body> 
 

 
</html>

+0

沒有,循環是很難的問題,'做而'和async/await一起工作就像每隔一個循環一樣(除非它的轉譯被破壞了 - 你能告訴我們轉發的ES5可能嗎?) – Bergi

+0

你把日誌語句放在哪裏?你能發表一個我們可以輕鬆運行自己的例子嗎?即使完整的代碼也會有幫助 – Bergi

+0

你的實際輸出是什麼樣的? – trusktr

回答

0

我沒有看到你asyncGenerator函數的嵌套do-while循環,但我確實看到asyncGenerator可以遞歸調用(有時是間接的),並且每次通話時一些新的異步await發生。不能保證這些await表達式中的任何一個將以相同的順序完成,因此不能保證console.log語句始終處於發生在代碼中的狀態。您的某些await表達式依賴於網絡(f.e. await listFiles(...)),並且網絡始終不可預測。有可能首先啓動的請求可能無法完成,因此遞歸函數調用並不總是按預期執行。

一兩件事你可以做的可能解決這個問題就是重構你的遞歸調用也使用await,所以遞歸調用可能看起來像:

await asyncGenerator(fileList.result.nextPageToken);