Return value in function from a promise block

I'm trying to write a function (using WebdriverJS lib) that iterates through a list of elements, checks the names and build an xpath locator that corresponds to that name. I simplified xpath locators here, so don't pay attention.

The issues I'm facing here are: 1) Calling this function returns undefined. As far as I understand, this is because the return statement is not in its place, but: 2) Placing it in the correct place where a synchronous code would normally work, doesn't work for async promises, hence calling this function will return the same undefined, but because the return statement fires before the "driver.findElement" statement.

How should I use the return statement here, if I want to get createdTask variable as a result of calling this function?

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

您可以先用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 + "]";
    });
}

Here you go, I cleaned it up a bit. This will actually return an error if one is experienced in the nested 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;
          }
        }
      });
  });
};

You call it using

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

You will not be able to return the value that you want from this function because when this function returns, the value is not defined yet.

This is not a problem that you try to return the value in the wrong place, but that you try to access it at the wrong time.

You have two options: you can either return a promise from this function, or this function can take a callback that would be called when the value is available.

Examples

This is not tested but should give you an idea on how to think about it.

Promise

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

and then you call it with:

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

Callback

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

and then you call it with:

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

More info

You can read some other answers that explain how promises and callbacks work if you're interested to know ore about it:

  • A detailed explanation on how to use callbacks and promises
  • Explanation on how to use promises in complex request handlers
  • An explanation of what a promise really is, on the example of AJAX requests
  • An explanation of callbacks, promises and how to access data returned asynchronously
  • 链接地址: http://www.djcxy.com/p/55358.html

    上一篇: 我如何返回承诺内的状态?

    下一篇: 从promise块返回函数中的值