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

Javascript 在forEach循环中创建承诺并在不嵌套的情况下使用它们,javascript,arrays,foreach,nested,promise,Javascript,Arrays,Foreach,Nested,Promise,我使用的是SeleniumWebDriver,我通过id获取特定元素。 在获得具有正确id的元素后,我尝试从列表中选择一个具有唯一属性值的元素 我已经设法获得了我需要的价值观,但我对我找到的解决方案不满意 情况: var attributeName = "bla"; var id = "icon"; var iconElementsPromise = driver.findElements(By.id(id)); // returns a promise containing an ar

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

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

情况:

var attributeName = "bla";
var id = "icon";    
var iconElementsPromise = driver.findElements(By.id(id)); // returns a promise containing an array with WebElements
解决方案1:嵌套
,然后
:这看起来非常错误,但它可以工作

  iconElementsPromise
    .then(function(iconElements) {
      iconElements.forEach(function(element, index) {
        element.getAttribute(attributeName)
          .then(function(attribute) {
            console.log("attribute: " + attribute);
          });
      });
    });
解决方案2:只有1个嵌套的
然后
:看起来更好,但现在我需要创建一个承诺数组,这是确定的。。。但我根本不想筑巢

  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)
我可以保持在相同的索引级别,并且不嵌套
然后
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个
然后
s并获取每个属性

解决方案2和3各有3个
,然后
s,并获取属性数组

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

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

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


示例很受欢迎。

使用
map
减少一个
然后
的简短版本,同时保持可读性

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

感谢您提示使用定位器,以前从未使用过,但会将其删除。看起来比在dom中导航更容易。在我的例子中,它实际上应该起作用。如果我理解正确,您可以使用array.map函数交换
forEach
循环,并将生成的数组(即Promise)放入
Promise.all
,它返回
然后打印的属性值。这本书可读性强,篇幅短,谢谢。