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

时间:2016-04-18 16:22:38

标签: javascript arrays foreach nested promise

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

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

情况:

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),我可以保持在同一个固定级别,并且不会嵌套then

  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 s并获取每个属性

解决方案2和3各有3 then s,并为我提供属性数组

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

我确实认为解决方案3或多或少是我想要的。但代码相当长。我觉得必须有一个更好,更可读和更短的方法来获取属性。

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

赞赏的例子。

2 个答案:

答案 0 :(得分:2)

3使用map缩短一个then同时保持其可读性的较短版本{/ 1}}

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

答案 1 :(得分:1)

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

// 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);
  })
});