Возвращаемое значение в функции из блока обещаний

Я пытаюсь написать функцию (используя библиотеку WebdriverJS lib), которая перебирает список элементов, проверяет имена и создает локатор xpath, соответствующий этому имени. Я упростил здесь локаторы xpath, так что не обращайте внимания.

Проблемы, с которыми я сталкиваюсь здесь: 1) Вызов этой функции возвращает неопределенное значение. Насколько я понимаю, это потому, что оператор return находится не на своем месте, а: 2) Поместить его в правильное место, где обычно работает синхронный код, не работает для асинхронных обещаний, следовательно, вызов этой функции вернет то же самое не определено, но потому что оператор return срабатывает перед оператором driver.findElement.

Как мне использовать оператор return здесь, если я хочу получить переменную createTask в результате вызова этой функции?

var findCreatedTask = function() {

    var createdTask;
    driver.findElements(By.xpath("//div[@id='Tasks_Tab']")).then(function(tasks) {

        for (var index = 1; index <= tasks.length; index++) {
            driver.findElement(By.xpath("//div[@id='Tasks_Tab'][" + index + "]//div[@class='task-title']")).getText().then(function(taskTitle) {
                if (taskTitle == "testName") {
                    createdTask = "//div[@id='Tasks_Tab'][" + index + "]";
                    return createdTask;
                }
            });
        }
    });
};

3 ответа

Решение

Вы могли бы сначала получить все тексты с promise.map а затем получить позицию с indexOf:

var map = webdriver.promise.map;

var findCreatedTask = function() {
    var elems = driver.findElements(By.xpath("//div[@id='Tasks_Tab']//div[@class='task-title']"));
    return map(elems, elem => elem.getText()).then(titles => {
      var position = titles.indexOf("testName") + 1;
      return "//div[@id='Tasks_Tab'][" + position + "]";
    });
}

Вот, пожалуйста, я немного прибрался. Это на самом деле вернет ошибку, если кто-то испытал во вложенных обещаниях:

var findCreatedTask = function() {
  var Promise = require('bluebird');
  var createdTask;
  return driver.findElements(By.xpath("//div[@id='Tasks_Tab']"))
    .then(function(tasks) {
      return Promise.map(tasks, function(task){
        return driver.findElement(By.xpath("//div[@id='Tasks_Tab'][" + index + "]//div[@class='task-title']")).getText()
      }).then(function(taskTitles){
        for (let i = 0; i < taskTitles.length; i++){
          if(taskTitles[i] === 'testName'){
            createdTask = "//div[@id='Tasks_Tab'][" + i + "]";
            return createdTask;
          }
        }
      });
  });
};

Вы называете это с помощью

findCreatedTask.then(function(res){
   //do your thing
}).catch(function(err){
   console.error(err.stack);
});

Вы не сможете вернуть нужное значение из этой функции, потому что, когда эта функция возвращает, значение еще не определено.

Это не проблема, что вы пытаетесь вернуть значение в неправильном месте, но вы пытаетесь получить к нему доступ в неправильное время.

У вас есть два варианта: вы можете либо вернуть обещание из этой функции, либо эта функция может принять обратный вызов, который будет вызван, когда значение будет доступно.

Примеры

Это не проверено, но должно дать вам представление о том, как об этом думать.

обещание

Версия с обещанием:

var findCreatedTask = function (callback) {

    var createdTask;
    return new Promise(function (resolve, reject) {

        driver.findElements(By.xpath("//div[@id='Tasks_Tab']")).then(function(tasks) {

            for (let index = 1; index <= tasks.length && !createdTask; index++) {
                driver.findElement(By.xpath("//div[@id='Tasks_Tab'][" + index + "]//div[@class='task-title']")).getText().then(function(taskTitle) {
                    if (taskTitle == "testName") {
                        createdTask = "//div[@id='Tasks_Tab'][" + index + "]";
                        resolve(createdTask);
                    }
                });
            }
        });
    });
};

а затем вы называете это с:

findCreatedTask().then(function (createdTask) {
  // you have your createdTask here
});

Перезвоните

Версия с обратным вызовом:

var findCreatedTask = function (callback) {

    var createdTask;
    driver.findElements(By.xpath("//div[@id='Tasks_Tab']")).then(function(tasks) {

        for (let index = 1; index <= tasks.length && !createdTask; index++) {
            driver.findElement(By.xpath("//div[@id='Tasks_Tab'][" + index + "]//div[@class='task-title']")).getText().then(function(taskTitle) {
                if (taskTitle == "testName") {
                    createdTask = "//div[@id='Tasks_Tab'][" + index + "]";
                    callback(null, createdTask);
                }
            });
        }
    });
};

а затем вы называете это с:

findCreatedTask(function (err, createdTask) {
  // you have your createdTask here
});

Больше информации

Вы можете прочитать некоторые другие ответы, которые объясняют, как работают обещания и обратные вызовы, если вам интересно узнать о них:

Другие вопросы по тегам