打破循环/承诺并从函数返回
Break the loop/promise and return from function
我有以下代码片段。
this.clickButtonText = function (buttonText, attempts, defer) {
var me = this;
if (attempts == null) {
attempts = 3;
}
if (defer == null) {
defer = protractor.promise.defer();
}
browser.driver.findElements(by.tagName('button')).then(function (buttons) {
buttons.forEach(function (button) {
button.getText().then(
function (text) {
console.log('button_loop:' + text);
if (text == buttonText) {
defer.fulfill(button.click());
console.log('RESOLVED!');
return defer.promise;
}
},
function (err) {
console.log("ERROR::" + err);
if (attempts > 0) {
return me.clickButtonText(buttonText, attempts - 1, defer);
} else {
throw err;
}
}
);
});
});
return defer.promise;
};
我的代码不时到达'ERROR::StaleElementReferenceError:陈旧的元素引用:元素未附加到页面文档'行,因此我需要重试并使用"try-1"参数调用我的函数。这是意料之中的行为。但一旦它到达"RESOLVED!"行,它就会不断迭代,所以我看到的smth是这样的:
button_loop:wrong_label_1
button_loop:CORRECT_LABEL
RESOLVED!
button_loop:wrong_label_2
button_loop:wrong_label_3
button_loop:wrong_label_4
问题是:如何在console.log('RESOLVED!')之后打破循环/承诺并从函数返回line?
除了抛出异常之外,没有任何方法可以停止或中断forEach()循环。如果您需要这样的行为,那么forEach()方法是错误的工具,请使用纯循环。
来源:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach
出于好奇,你想完成什么?对我来说,你似乎想根据文本点击一个按钮,所以你会在页面上的所有按钮中迭代,直到找到与文本匹配的按钮。
看起来您在非角度页面上使用量角器,如果您在规范文件中使用browser.ignoreSynchronization = true;
或在conf.js
文件中使用onPrepare块,会更容易,因此您仍然可以利用量角器API,它有两个元素定位器,可以轻松实现这一点。
this.clickButtonText = function(buttonText) {
return element.all(by.cssContainingText('button',buttonText)).get(0).click();
};
或
this.clickButtonText = function(buttonText) {
return element.all(by.buttonText(buttonText)).get(0).click();
};
如果有其他原因想循环浏览按钮,我可以写一个更复杂的解释,使用bluebird来循环浏览元素。它是一个非常有用的解决承诺的库。
您创建了一个额外的延迟对象,这让您自己更加困难。如果单击失败,您可以使用promise本身重试操作。
var clickOrRetry = function(element, attempts) {
attempts = attempts === undefined ? 3 : attempts;
return element.click().then(function() {}, function(err) {
if (attempts > 0) {
return clickOrRetry(element, attempts - 1);
} else {
throw new Error('I failed to click it -- ' + err);
}
});
};
return browser.driver.findElements(by.tagName('button')).then(function(buttons) {
return buttons.forEach(function(button) {
return clickOrRetry(button);
});
});
一种方法是(在每次"尝试"时)构建一个承诺链,该承诺链在失败时继续,但在成功时跳到最后。这样的链条将是一般的形式。。。
return initialPromise.catch(...).catch(...).catch(...)...;
并且使用javascript数组方法CCD_ 3以编程方式构造简单。
在实践中,会使代码变得庞大
- 调用异步CCD_ 4的需要然后执行用于匹配文本的相关联的测试
- 需要编排3次尝试
但仍然不太笨重。
据我所知,你想要这样的东西:
this.clickButtonText = function (buttonText, attempts) {
var me = this;
if(attempts === undefined) {
attempts = 3;
}
return browser.driver.findElements(by.tagName('button')).then(function(buttons) {
return buttons.reduce(function(promise, button) {
return promise.catch(function(error) {
return button.getText().then(function(text) {
if(text === buttonText) {
return button.click(); // if/when this happens, the rest of the catch chain (including its terminal catch) will be bypassed, and whatever is returned by `button.click()` will be delivered.
} else {
throw error; //rethrow the "no match" error
}
});
});
}, Promise.reject(new Error('no match'))).catch(function(err) {
if (attempts > 0) {
return me.clickButtonText(buttonText, attempts - 1); // retry
} else {
throw err; //rethrow whatever error brought you to this catch; probably a "no match" but potentially an error thrown by `button.getText()`.
}
});
});
};
注:
- 使用这种方法,不需要传入延迟对象。事实上,不管你采取什么方法,这都是不好的做法。失败很少是必要的,更不需要四处传递
- 在reduce构建捕获链之后,我移动了终端
catch(... retry ...)
块作为最终捕获。这比button.getText().then(onSucccess, onError)
结构更有意义,后者会在第一次匹配buttonText失败时导致重试;这在我看来是不对的 - 您可以将终端捕获进一步下移,以便捕获
browser.driver.findElements()
抛出的错误(用于重试),尽管这可能有些过头了。如果browser.driver.findElements()
失败一次,它很可能会再次失败 - "重试"策略也可以通过
.reduce()
过程构建的捕获链的3倍连接来实现。但你会看到一个更大的记忆尖峰 - 为了清楚起见,我省略了各种console.log(),但它们应该很容易重新插入
- ES6构造函数返回基类的实例
- 从函数返回角度承诺
- 如何从jquery函数返回变量
- 根据是否解析了 Promise 从函数返回值
- Javascript函数返回未定义
- 如果函数返回True,则显示Javascript按钮
- Google Sheet自定义函数返回0
- 从Ajax函数返回值
- 使用for循环从Javascript中的函数返回多个值
- 谷歌地图:函数返回未定义的值在console.log中运行良好
- 从函数中的函数返回数组时出错
- 如何从嵌套的API函数返回值
- 从Mongoose结果匿名函数返回父函数
- 函数返回错误'令牌{'
- Jquery函数返回订单问题
- Mocha/Chai测试链接到函数返回断言错误
- 从异步函数返回值
- 函数返回后更新变量
- 我如何才能继续'如果'语句来比较作为参数的多个函数返回值
- 将外部函数返回的id传递给内部函数