在forEach循环中创建promise,并在不嵌套的情况下使用它们

Creating promises in a forEach loop and using them without nesting

本文关键字:情况下 嵌套 循环 forEach 创建 promise      更新时间:2023-09-26

我使用的是selenium-webdriver,我通过id获取特定元素。在获得具有正确id的元素后,我尝试从列表中选择一个具有唯一属性值的元素。

我已经设法达到了我需要的价值,但我对我找到的解决方案不满意。

情况:

var attributeName = "bla";
var id = "icon";    
var iconElementsPromise = driver.findElements(By.id(id)); // returns a promise containing an array with WebElements

解决方案1:嵌套then的:这看起来很错误,但它有效。

  iconElementsPromise
    .then(function(iconElements) {
      iconElements.forEach(function(element, index) {
        element.getAttribute(attributeName)
          .then(function(attribute) {
            console.log("attribute: " + attribute);
          });
      });
    });

解决方案2:只有1个嵌套的then:它看起来更好,但现在我需要创建一个Promises数组,这是可以的……但我希望根本不嵌套

  iconElementsPromise
    .then(function(iconElements) {
      var promises = [];
      iconElements.forEach(function(element, index) {
        promises.push(element.getAttribute("tag"));
      });
      return promises;
    })
    .then(function(promises) {
      Promise.all(promises)
        .then(function(attributes) {
          console.log("attributes: " + attributes);
        });
    });

解决方案3:通过返回Promise.all(promises),我可以保持在相同的indet级别,并且不嵌套then s。

  iconElementsPromise
    .then(function(iconElements) {
      var promises = [];
      iconElements.forEach(function(element, index) {
        promises.push(element.getAttribute(attributeName));
      });
      return promises;
    })
    .then(function(promises) {
      return Promise.all(promises);
    })
    .then(function(attributes) {
      console.log("attributes: " + attributes);
    });

解决方案1有2个then,并获得每个属性

解决方案2和3各有3个then,并为我获取属性数组

获取每个属性或只获取数组是可以的。

我相信解决方案3或多或少是我想要的。但代码相当长。我觉得必须有一种更好、更可读、更短的方法来获取属性。

所以我的问题是:**使用promise获取属性的最佳方式是什么?**

示例值得赞赏。

3的一个较短版本,使用map减少一个then,同时保持其可读性

iconElementsPromise
.then(function(iconElements) {
  return Promise.all(iconElements.map(function(element){
      return element.getAttribute(attributeName);
  }));
})
.then(function(attributes) {
  console.log("attributes: " + attributes);
});

如果您的目标是选择一个具有唯一属性的元素,那么将该属性包含在定位器中会更容易:

// select with an XPath the first element having an attribute "bla" and a parent with the "icon" id
var element = driver.findElement(By.xpath("id('icon')/*[@bla]"));
// select with a CSS selector the first element having the attribute "bla" and a parent with the "icon" id
var element = driver.findElement(By.cssSelector("#icon > [bla]"));

但是,如果你真的想要所有的属性,那么一个简单的解决方案是使用webdriver.promise.map:

var webdriver = require('selenium-webdriver');
var promise = webdriver.promise;
var By = webdriver.By;
var Key = webdriver.Key;
var EC = webdriver.until;
var driver = new webdriver.Builder()
  .withCapabilities({'browserName': 'firefox'})
  .build();
driver.get('http://stackoverflow.com/');
driver.findElements(By.xpath('//a')).then(function(elts) {
  promise.map(elts, function(elt) {
    return elt.getAttribute("href");
  }).then(function(links) {
    console.log(links);
  })
});
相关文章: