如何以同步方式制作 Promise API?

How to make Promise API in a synchronous way?

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

getTitle() 安排一个命令来检索当前页面的标题。这个APIreturn一个webdriver.promise.Promise

例如 selenium-webdriver 我做

driver.getTitle().then(function(title) {
   .....
 });

driver.findElement(webdriver.By.name('q')).sendKeys('webdriver');

如何做到完全同步API(使API Promise 同步?),像这样

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

更新(Benjamin Gruenbaum 回复):

使用 yield with Promise.coroutine from 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

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

如果这是你的目标,你可以使用 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 returns 一个承诺:

Returns

webdriver.promise.Promise<T>

A promise that will be fulfilled with the first truthy value returned by the condition function, or rejected if the condition times out.

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

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

...标题最多等待 10 秒。或者,如果您的目标不是真正获得标题,而是获得名称为 q 的元素,那么这几乎与上面 wait 的示例完全相同:

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

如果您使用的是新版本的 NodeJS(如 io.js(节点 3.0)或更高版本),您可以将 yield 与来自 bluebird 的 Promise.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();
    // ...
})();