2015-11-04 74 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);