Valor de retorno na function de um bloco de promise

Eu estou tentando escrever uma function (usando WebdriverJS lib) que itera através de uma lista de elementos, verifica os nomes e construir um xpath locator que corresponde a esse nome. Eu simplifiquei os localizadores de xpath aqui, então não preste atenção.

Os problemas que estou enfrentando aqui são: 1) Chamar esta function retorna indefinido. Tanto quanto eu entendo, isso é porque a declaração de retorno não está em seu lugar, mas: 2) Colocá-lo no lugar correto onde um código síncrono normalmente funcionaria, não funciona para promises assíncronas, portanto, chamar esta function retornará o mesmo indefinido, mas porque a instrução de retorno é acionada antes da instrução “driver.findElement”.

Como devo usar a declaração de retorno aqui, se eu quiser obter a variável Task criada como resultado de chamar essa 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; } }); } }); }; 

Você pode primeiro obter todos os textos com promise.map e depois obter a posição com 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 + "]"; }); } 

Aqui vai, eu limpei um pouco. Isso realmente retornará um erro se houver uma experiência nas promises aninhadas:

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

Você chama isso usando

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

Você não poderá retornar o valor que você quer desta function porque quando esta function retorna, o valor não é definido ainda.

Este não é um problema que você tente devolver o valor no lugar errado, mas que você tente acessá-lo na hora errada.

Você tem duas opções: você pode retornar uma promise dessa function ou essa function pode receber um retorno de chamada que seria chamado quando o valor estivesse disponível.

Exemplos

Isso não é testado, mas deve lhe dar uma idéia de como pensar sobre isso.

Promessa

Versão com 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); } }); } }); }); }; 

e então você chama isto com:

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

Ligue de volta

Versão com retorno de chamada:

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

e então você chama isto com:

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

Mais informações

Você pode ler algumas outras respostas que explicam como promises e retornos de chamada funcionam se você estiver interessado em saber mais sobre isso:

  • Uma explicação detalhada sobre como usar retornos de chamada e promises
  • Explicação sobre como usar promises em manipuladores de solicitação complexos
  • Uma explicação do que realmente é uma promise, no exemplo de solicitações AJAX
  • Uma explicação de retornos de chamada, promises e como acessar dados retornados de forma assíncrona