承诺中的 NighmareJS 循环操作不会等待结果

NighmareJS Looping Actions In A Promise Doesn't Wait Results

我是新手。我刚刚开始使用它们,以便我可以从远程 API 获取结果并在我的 NightmareJS 代码中使用它们。该请求效果很好。问题来自我的噩梦代码。我在 Nightmare 中使用 vo 库。通常我把 yield 放在我的噩梦电话前面。在请求的 .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 --inspect --debug-brk ./myscript.js

打开 google Chrome 的新版本并导航至 about:inspect

此 window 包含一个名为 Open dedicated DevTools for Node 的 link,单击此 link。当您启动和停止节点进程时,调试器将自动重新连接。

当您因错误而中断时,您可以看到哪里出了问题。

[更新]

使用下面的代码你可以玩promises,有两种方式开始处理一些异步函数:

  1. 一次全部启动
  2. 开始第一个,等待它完成,然后开始下一个

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

//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"