javascript - NightmareJS 在 Promise 中循环操作不等待结果

标签 javascript node.js promise nightmare

我对 Promise 很陌生。我刚刚开始使用它们,以便我可以从远程 API 获取结果并在我的 NightmareJS 代码中使用它们。该请求效果很好。问题出在我的 Nightmare 代码上。我将 vo 库与 Nightmare 一起使用。通常我会将 yield 放在 Nightmare 调用前面。在请求的 .then() 中,我无法使用 yield。我的 Nightmare 调用仍在工作,但一旦我将它们放入循环中,循环就会非常快地迭代所有元素,而无需等待它们完成。下面是一个 forEach 循环。我还尝试了 for 循环。

let keyword = 'horror games';
let kwOptions = {
    qs: {
        query: keyword,
    },
    url: "https://api.example.com/",
    json: true
};
rp(kwOptions)
    .then(function(relKeywords){
        console.log(relKeywords[1]);
        relKeywords[1].forEach(function (element) {
            console.log('searching for: ' + element);
            nightmare.evaluate(function() {
                document.querySelector('input[cloom-label="query"]').setAttribute('value', ''); // Clear search box
            });
            nightmare.type('input[cloom-label="query"]', ' ' + element + '\u000d');
            nightmare.click('span._5d a');
            nightmare.wait(5000)
        });
    })
    .catch(function(err){
        console.log("Couldn't get keywords: "+err);
    });

必须有一些我可以使用的其他模式,以便我可以使用 yield 或其他方式来修复循环中的 Nightmare。

最佳答案

下面的方法有效吗?应该按照documentation .

const processValuesSerial = (v,process) => { 
  if(v === undefined){return Promise.resolve("nothing to do"); }
  if(v.length === undefined){return Promise.resolve("nothing to do"); }  
  if(v.length === 0){return Promise.resolve("nothing to do"); }
  if(v.length === 1){return process(Promise.resolve(v[0]),v[0]); }
  return v
    .map(x => Promise.resolve(x))
    .reduce(process)
    .then(//bug fix: last item was not processed
      x=>
        process(
          Promise.resolve(x)
          ,Promise.resolve(v.slice(-1))
        )
    )
}
let keyword = 'horror games';
let kwOptions = {
    qs: {
        query: keyword,
    },
    url: "https://api.example.com/",
    json: true
};
rp(kwOptions)
.then(function(relKeywords){
  return processValuesSerial(
    relKeywords[1]
    ,(acc, element) =>
      acc
      .then(x => {
        console.log('searching for: ' + x);
        //return promise like item from nightmare
        return nightmare.evaluate(function() {
            document.querySelector('input[cloom-label="query"]').setAttribute('value', ''); // Clear search box
        })
        .type('input[cloom-label="query"]', ' ' + x + '\u000d')
        .click('span._5d a')
        .wait(5000);
      })
      .then(x => element)
  );
})
.catch(function(err){
  console.log("Couldn't get keywords: "+err);
});

调试技巧:

使用调试和中断标志启动 Node :

node --inspect --debug-brk ./myscript.js

打开新版本的 Google Chrome 浏览器并导航至 about:inspect

此窗口包含一个名为打开 Node 专用 DevTools 的链接,请单击此链接。当您启动和停止 Node 进程时,调试器将自动重新连接。

当您遇到错误时,您可以看到哪里出了问题。

[更新]

通过以下代码,您可以使用 Promise,有 2 种方法可以开始处理一些异步函数:

  1. 立即启动所有这些
  2. 启动第一个,等待其完成,然后开始下一个

代码中添加了一些注释,您可以在浏览器开发工具的控制台选项卡中运行此代码

//for each item in array v run process 
//  but only run the next item in v when the first item is resolved
var processValuesSerial = (v,process) => {
  //checking valid imput
  if(v === undefined){return Promise.resolve("nothing to do"); }
  if(v.length === undefined){return Promise.resolve("nothing to do"); }
  if(v.length === 0){return Promise.resolve("nothing to do"); }
  //only one item, no need to reduce
  if(v.length === 1){return process(Promise.resolve(v[0]),v[0]); }
  //at least 2 items in v, process them
  return v
    .map(x => Promise.resolve(x))
    .reduce(process)
    //last item will not be passed to process function in reduce
    //  manually execute the last process function on this item
    .then(
      x=>
        process(
          Promise.resolve(x)
          ,Promise.resolve(v.slice(-1))
        )
    )
}
//functions that do something
var logValue =
  (value,message) =>
    //log value and return it
    console.log(message,value) || value
//asynchronous function
var waitFor = 
  (howLong,returnValue) =>
    //returning a promise that resolves after waiting for "howLong"
    new Promise(
      (resolve,reject)=>
        setTimeout(x => resolve(returnValue),howLong)
    )
;


//for each value I would like to do something asynchronous.
//  for example
var values = [1,2,3,4,5];

/**
 * Problem with promises is that they start immediately so the 
 * following example will start 1,2,3,4,5 imediately and then
 * what we want is do(1).then(do(2)).then(do(3))
 */
Promise.all(
  values.map(
    x =>
      Promise.resolve(x)
      .then(
        x => logValue(x,"+++++At the same time Starting:")
      )
      .then(
        x => waitFor(x*500,x)
      )
      .then(
        x => logValue(x,"+++++At the same time Finished:")
      )
  )
)
.then(x => console.log("finished promises at the same time"))

//the following will not start everything at the same time
//   it will do(1).then(do(2)).then(do(3))
processValuesSerial(
  values
  //reducer function, acc is current value as a promise
  //  item is the next value as a promise
  ,(acc,item)=>
    //acc is a promise that resolves to "item" (=1 then 2 then 3 then 4 then 5)
    //  the first time it is 1, the second time it is whatever we return here
    //  we return a promise
    acc.then(
      //acc is resolved so we should have a value of 1, then 2 ...
      //  if we return the right value
      x=>logValue(x,"XXXXX In serie Starting:")
    )
    .then(
      //return a promise that waits
      x=>waitFor(x*500,x)
    )
    .then(
      x=>logValue(x,"XXXXX In serie Finished:")
    )
    //return next item
    .then(x=>item)
)
"OOOOOO Finished running synchronous code"

关于javascript - NightmareJS 在 Promise 中循环操作不等待结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46577899/

相关文章:

javascript - 如何仅当 glymphicon 图标具有键盘焦点时才应用 CSS 样式?

javascript - 用户通过输入框输入 document.getElementById

javascript - Bluebird(或其他 Promise 库)保留 Promise 错误堆栈跟踪

node.js - Discord.js awaitReaction 链式 promise 在 message.react 收集 react 后 promise 未解决

javascript - 在 'for' 循环中使用 Jquery Promise() 等待效果完成后再开始下一个效果

javascript - 使用搜索参数创建分页链接

javascript - 如何删除/取消设置 JavaScript 对象的属性?

node.js - 编写一个 io.js 兼容的 npm 模块

html - Nodejs 和 heroku - Heroku 找不到我的 css 文件和我的图像文件,但在本地主机端口 : 3000 上工作正常

node.js - Heroku Node.js 错误 heroku[路由器] : at=error code=H10 desc ="App crashed" method=GET path ="/"