我对 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 种方法可以开始处理一些异步函数:
- 立即启动所有这些
- 启动第一个,等待其完成,然后开始下一个
代码中添加了一些注释,您可以在浏览器开发工具的控制台选项卡中运行此代码
//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/