如何以同步方式制作Promise API

How to make Promise API in a synchronous way?

本文关键字:Promise API 方式制 同步      更新时间:2023-09-26

我使用selenium-webdriver进行NodeJS测试。我想以同步的方式制作selenium-webdriver API,使我的测试非常简洁。

getTitle()调度一个命令来检索当前页面的标题。这个API返回一个webdriver.promise.Promise

例如,在selenium-webdriver中,我使用

driver.getTitle().then(function(title) {
   .....
 });
driver.findElement(webdriver.By.name('q')).sendKeys('webdriver');

我如何做完全同步的API(使API承诺同步?),像这样

var titleElement = driver.getTitle();
var qElement= driver.findElement(webdriver.By.name('q'));
qElement.sendKeys('webdriver');

Update (with Benjamin Gruenbaum response):

使用yield with Promise。bluebird API的协程

function myBrowser() {
}
myBrowser.prototype.getTitle = Promise.coroutine(function* (driver) {
    var title = yield driver.getTitle(); // yield makes it wait
    console.log('prototype.getTitle: ' + title)
    return title;
});
var driver = createDriver();
driver.get('https://www.google.fr/')
driver.getTitle().then(function(title) {
    console.log('getTitle: ' + title)
 });
// Use bluebird API
var mb = new myBrowser();
var title = mb.getTitle(driver)
// KO, It' an object Promise, not string title
console.log('main Process: ' + title)

输出
[INFO:CONSOLE(0)] main Process: [object Promise] 
[INFO:CONSOLE(0)] getTitle: Google
[INFO:CONSOLE(0)] prototype.getTitle: Google

如果您使用的是新版本的NodeJS(如io.js (node 3.0)或更高版本),您可以将bluebird的yieldPromise.coroutine一起使用(这可以通过运行--harmony-generators标志在旧版本中激活):

Promise.coroutine(function*(){
    var title = yield driver.getTitle(); // yield makes it wait
    yield driver.findElement(By.name("q")).sendKeys("webdriver");
})();

如果你像t.j.建议的那样使用babel,你也可以使用异步函数:

(async function(){
    let title = await driver.getTitle();
    // ...
})();

你不能,除非API以某种方式使它成为可能(见下文)。如果正在使用的Selenium API被设计为异步工作,则不能强制它是同步的。我找不到您正在使用的getTitle调用的文档,但是因为它返回一个承诺,并且承诺的值只能通过then回调访问(并且当您收到它时承诺可能尚未解决),并且由于这些回调总是异步调用(如果它们是承诺/a +兼容),您将不得不编写期望异步的代码。

你可以让这个回调更简洁,如果这是你的目标,通过使用ES6的箭头函数:

driver.getTitle().then((title) => {
   // .....
});
driver.findElement(webdriver.By.name('q')).sendKeys('webdriver');

我认为现在在Node中使用箭头函数,你必须使用像Babel这样的转译器。


API 可能提供了一个允许您这样做的特性:您可能能够使用wait,但是很难分辨,因为文档被破坏了:示例显示wait返回正在等待的东西(按钮):
var button = driver.wait(until.elementLocated(By.id('foo'), 10000);
button.click();

…但是文档清楚地说wait返回一个承诺:

webdriver.promise.Promise<T>

使用条件函数返回的第一个真值来完成的承诺,如果条件超时则拒绝。

如果是后者错了(看起来很有可能),那么

var title = driver.wait(driver.getTitle(), 10000);

…要等十秒钟才能拿到头衔。或者,如果您的目标不是真正获得标题,而是获得名称为q的元素,那么这几乎与上面的wait的示例完全相同:

driver.wait(until.elementLocated(By.name('q'), 10000).sendKeys('webdriver');