咨询:for循环内.then语句未逐次执行的解决方法
解决循环中异步
.then回调延迟执行的问题 这个问题是JavaScript闭包与事件循环的经典坑,我来帮你拆解原因,再给几个实用的解决方案:
问题根源
你用var定义了inactiveOpptyName,而var是函数级作用域变量——循环里的所有.then回调共享同一个inactiveOpptyName的引用。当for循环快速执行完毕时,所有异步回调还没触发,此时inactiveOpptyName已经被更新成数组最后一个元素的值,所以所有回调都会复用这个值,自然达不到逐个筛选的效果。
另外,异步操作的执行逻辑是:先跑完所有同步循环代码,再处理队列里的.then回调,这也进一步放大了问题。
解决方案1:用let替代var(最简单)
let是ES6引入的块级作用域变量,每次循环迭代都会创建一个新的inactiveOpptyName绑定,每个.then回调都会捕获当前循环的变量值:
//获取全部机会列表 commonFunction.getAllTextByXpath(dealWorkspace.opportunityNameXPath).then(function (inactiveOpptyList) { //识别权限为'Admin'且状态为'On Hold'的机会 for (let j = 0; j < inactiveOpptyList.length; j++) { // var 改成 let let inactiveOpptyName = inactiveOpptyList[j]; // var 改成 let //获取机会的权限 dealWorkspace.getPermissionOppty(inactiveOpptyName).then(function (permission) { if (permission === 'Admin') { //获取机会的状态 dealWorkspace.getStatusByOppty(inactiveOpptyName).then(function (status) { //对符合条件的机会执行带Cancel选项的删除操作 if (status === 'On Hold') { inactiveOppty.deleteOppty(inactiveOpptyName, 'Cancel'); } }); } }); } });
解决方案2:用IIFE创建闭包(兼容旧环境)
如果你的环境还不支持ES6,可以用立即执行函数表达式(IIFE)为每次循环创建独立作用域,把当前的inactiveOpptyName传递进去:
//获取全部机会列表 commonFunction.getAllTextByXpath(dealWorkspace.opportunityNameXPath).then(function (inactiveOpptyList) { //识别权限为'Admin'且状态为'On Hold'的机会 for (var j = 0; j < inactiveOpptyList.length; j++) { (function(currentOpptyName) { // 用IIFE包裹,传入当前元素 //获取机会的权限 dealWorkspace.getPermissionOppty(currentOpptyName).then(function (permission) { if (permission === 'Admin') { //获取机会的状态 dealWorkspace.getStatusByOppty(currentOpptyName).then(function (status) { //对符合条件的机会执行带Cancel选项的删除操作 if (status === 'On Hold') { inactiveOppty.deleteOppty(currentOpptyName, 'Cancel'); } }); } }); })(inactiveOpptyList[j]); // 把当前循环的元素传进IIFE } });
解决方案3:用async/await(最优雅,推荐)
Protractor本身支持async/await语法,用它可以把异步代码写成同步风格,彻底避免闭包和回调嵌套的问题,可读性拉满:
//获取全部机会列表 commonFunction.getAllTextByXpath(dealWorkspace.opportunityNameXPath).then(async function (inactiveOpptyList) { // 加上async标记 //识别权限为'Admin'且状态为'On Hold'的机会 for (let j = 0; j < inactiveOpptyList.length; j++) { let inactiveOpptyName = inactiveOpptyList[j]; //等待获取权限 let permission = await dealWorkspace.getPermissionOppty(inactiveOpptyName); if (permission === 'Admin') { //等待获取状态 let status = await dealWorkspace.getStatusByOppty(inactiveOpptyName); if (status === 'On Hold') { inactiveOppty.deleteOppty(inactiveOpptyName, 'Cancel'); } } } });
还能进一步简化成for...of循环:
commonFunction.getAllTextByXpath(dealWorkspace.opportunityNameXPath).then(async function (inactiveOpptyList) { for (const inactiveOpptyName of inactiveOpptyList) { const permission = await dealWorkspace.getPermissionOppty(inactiveOpptyName); if (permission === 'Admin') { const status = await dealWorkspace.getStatusByOppty(inactiveOpptyName); if (status === 'On Hold') { inactiveOppty.deleteOppty(inactiveOpptyName, 'Cancel'); } } } });
这种写法不仅解决了你的问题,还摆脱了“回调地狱”,逻辑清晰易懂。
内容的提问来源于stack exchange,提问作者Chinaren
相关产品推荐
相关产品推荐

