CefSharp Javascript 异步响应太快
CefSharp Javascript async response too fast
我的方法是访问每个 link,如果所有访问都从中接收 return 值。
问题是,当我启动代码时,我立即得到一个响应,显然是空的,因为并不是所有的 link 都被访问了。
private async void ibtn_start_visiting_Click(object sender, EventArgs e)
{
string js = "var ele = document.querySelectorAll('#profiles * .tile__link');document.getElementsByClassName('js-scrollable')[0].scrollBy(0,30);ele.forEach(function(value,index){setTimeout(function(){if(index < ele.length-1){ele[index].click();}else{document.querySelectorAll('.search-results__item').forEach(e => e.parentNode.removeChild(e));document.getElementsByClassName('js-close-spotlight')[0].click();return 'hallo';}},1000 * index)})";
await browser.EvaluateScriptAsync(js).ContinueWith(x =>
{
var response = x.Result;
if (response.Success)
{
this.Invoke((MethodInvoker)delegate
{
var res = (string)response.Result;
Console.WriteLine("Response: " + res);
});
}
else {
Console.WriteLine("NO");
}
});
}
这是javascript:
var ele = document.querySelectorAll('#profiles * .tile__link');
document.getElementsByClassName('js-scrollable')[0].scrollBy(0,30);
ele.forEach(function(value,index){
setTimeout(function(){
if(index < ele.length-1){
ele[index].click();
}
else{
document.querySelectorAll('.search-results__item').forEach(e => e.parentNode.removeChild(e));
document.getElementsByClassName('js-close-spotlight')[0].click();
alert('hallo');
}
},1500 * index)
})
哦,我明白了。您的 javascript 正在使用 setTimeout
,这相当于使您传递给它的函数也是异步的。 CefSharp 不知道那些 setTimeout
任务何时完成,因此早期 return。挂起的 javascript 代码最终会执行。要知道什么时候完成,您有几个选择:
- 通过完全摆脱
setTimeout
让您的异步 javascript 代码同步。
- 在您的异步 javascript 代码中设置一些全局变量,并在 C# 中定期检查您的网页以查看是否设置了该变量。
- 注册一些 JS 处理程序并在异步 javascript 完成时调用它。
#3 是我的最爱,因此您可以像这样在 C# 中注册该处理程序:
public class CallbackObjectForJs{
public void showMessage(string msg){
// we did it!
}
}
webView.RegisterJsObject("callbackObj", new CallbackObjectForJs());
你的 JS 可能看起来像:
var totalTasks = 0;
function beginTask() {
totalTasks++;
}
function completeTask() {
totalTasks--;
if (totalTasks === 0) {
callbackObj("we finished!"); // this function was registered via C#
}
}
var ele = document.querySelectorAll('#profiles * .tile__link');
document.getElementsByClassName('js-scrollable')[0].scrollBy(0,30);
ele.forEach(function(value,index){
beginTask(); // NEW
setTimeout(function(){
... // work
completeTask();
}, 1500 * index);
})
要使此更清洁,您可能需要查看 Javascript 的 Promise.all()
。
我的方法是访问每个 link,如果所有访问都从中接收 return 值。 问题是,当我启动代码时,我立即得到一个响应,显然是空的,因为并不是所有的 link 都被访问了。
private async void ibtn_start_visiting_Click(object sender, EventArgs e)
{
string js = "var ele = document.querySelectorAll('#profiles * .tile__link');document.getElementsByClassName('js-scrollable')[0].scrollBy(0,30);ele.forEach(function(value,index){setTimeout(function(){if(index < ele.length-1){ele[index].click();}else{document.querySelectorAll('.search-results__item').forEach(e => e.parentNode.removeChild(e));document.getElementsByClassName('js-close-spotlight')[0].click();return 'hallo';}},1000 * index)})";
await browser.EvaluateScriptAsync(js).ContinueWith(x =>
{
var response = x.Result;
if (response.Success)
{
this.Invoke((MethodInvoker)delegate
{
var res = (string)response.Result;
Console.WriteLine("Response: " + res);
});
}
else {
Console.WriteLine("NO");
}
});
}
这是javascript:
var ele = document.querySelectorAll('#profiles * .tile__link');
document.getElementsByClassName('js-scrollable')[0].scrollBy(0,30);
ele.forEach(function(value,index){
setTimeout(function(){
if(index < ele.length-1){
ele[index].click();
}
else{
document.querySelectorAll('.search-results__item').forEach(e => e.parentNode.removeChild(e));
document.getElementsByClassName('js-close-spotlight')[0].click();
alert('hallo');
}
},1500 * index)
})
哦,我明白了。您的 javascript 正在使用 setTimeout
,这相当于使您传递给它的函数也是异步的。 CefSharp 不知道那些 setTimeout
任务何时完成,因此早期 return。挂起的 javascript 代码最终会执行。要知道什么时候完成,您有几个选择:
- 通过完全摆脱
setTimeout
让您的异步 javascript 代码同步。 - 在您的异步 javascript 代码中设置一些全局变量,并在 C# 中定期检查您的网页以查看是否设置了该变量。
- 注册一些 JS 处理程序并在异步 javascript 完成时调用它。
#3 是我的最爱,因此您可以像这样在 C# 中注册该处理程序:
public class CallbackObjectForJs{
public void showMessage(string msg){
// we did it!
}
}
webView.RegisterJsObject("callbackObj", new CallbackObjectForJs());
你的 JS 可能看起来像:
var totalTasks = 0;
function beginTask() {
totalTasks++;
}
function completeTask() {
totalTasks--;
if (totalTasks === 0) {
callbackObj("we finished!"); // this function was registered via C#
}
}
var ele = document.querySelectorAll('#profiles * .tile__link');
document.getElementsByClassName('js-scrollable')[0].scrollBy(0,30);
ele.forEach(function(value,index){
beginTask(); // NEW
setTimeout(function(){
... // work
completeTask();
}, 1500 * index);
})
要使此更清洁,您可能需要查看 Javascript 的 Promise.all()
。