JavaScript async/await and do/while loop

JavaScript async/await and do/while loop

本文关键字:while loop do await async JavaScript and      更新时间:2023-09-26

当外部循环迭代次数少于大约100次时,以下脚本将按预期运行。如果外部循环迭代几千次,我可以看到我的console.log被混淆了。例如:

  • 3x外环输出
  • 1x内环输出
  • 1x外环输出//不应发生,因为所有外环输出在内部循环输出之前

  • 3x外环输出
  • 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"answers"apiKey"
  • 在此期间,我用递归替换了外部do/while循环函数调用,但输出仍然很奇怪
  • 我不知道如何包含browser.js和runtime.js,因此,脚本标记仍然包含我的路径
  • 此外,我不确定这是否在片段中起作用:type="text/babel"src="js/driverlights.js"在第4个script标记中

"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 = 'TEST@TEST.COM';
  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 {
	margin: 5% 0;
	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 {
	width: 200px;
	margin-top: 10px;
}
<!DOCTYPE>
<html>
<head>
	<title>Drive Rights</title>
	<link rel="stylesheet" href="style.css">
	<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css">
	<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
	<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.min.js"></script>
  
	<script type="text/javascript" src="js/browser.js"></script>
	<script type="text/babel" src="js/driverights.js"></script>
	<script type="text/javascript" src="js/runtime.js"></script>
	<script src="https://apis.google.com/js/client.js"></script>
</head>
<body class="cover full">
	<div class="container">
		<div class="jumbotron coverbox clearfix">
			<h1>Drive Rights</h1>
			<p>
				Change file permissions for specific user.
			</p>
			<hr class="separator">
			<div id="info" class="clearfix">
				<p>
					First click login, then start.
				</p>
				<p class="text-center">
					<button type="button" class="btn btn-primary btn-lg" id="init">
						Login
					</button></br>
					<button type="button" class="btn btn-primary btn-lg" id="start">
						Start
					</button>
				</p>
			</div>
			<div id="progress"></div>
		</div>
</body>
</html>

我在asyncGenerator函数中没有看到嵌套的do while循环,但我确实看到asyncGenerator可以递归调用(有时是间接调用),在每次调用过程中都会发生一些新的异步await。不能保证这些await表达式中的任何一个都将以相同的顺序完成,因此也不能保证console.log语句总是按它们在代码中发生的顺序完成。你的一些await表达式依赖于网络(例如await listFiles(...)),而网络并不总是那么可预测。首先开始的请求可能不会首先完成,因此递归函数调用不会总是按预期执行。

要解决这个问题,可以做的一件事是重构递归调用,使其也使用await,因此递归调用可能看起来像:

await asyncGenerator(fileList.result.nextPageToken);