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

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

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

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

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

Ответ 1

Сначала вы можете получить все тексты с 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 + "]";
    });
}

Ответ 2

Здесь вы идете, я немного почистил его. Это действительно вернет ошибку, если у вас есть опыт в вложенном promises:

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

Ответ 3

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

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

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

Примеры

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

Promise

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

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

Callback

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

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

Подробнее

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