承诺中的 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,有两种方式开始处理一些异步函数:
- 一次全部启动
- 开始第一个,等待它完成,然后开始下一个
代码中添加了一些注释,您可以运行在您的浏览器控制台选项卡中的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"
我是新手。我刚刚开始使用它们,以便我可以从远程 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,有两种方式开始处理一些异步函数:
- 一次全部启动
- 开始第一个,等待它完成,然后开始下一个
代码中添加了一些注释,您可以运行在您的浏览器控制台选项卡中的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"