首页 > 解决方案 > CefSharp Javascript异步响应太快

问题描述

我的方法是访问每个链接,如果所有链接都被访问以接收返回值。问题是,当我启动代码时,我会立即得到响应,显然是空的,因为并非所有链接都被访问过。

    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)
})

标签: c#cefsharp

解决方案


我懂了。您的 javascript 正在使用setTimeout,这相当于使您传递给它的函数也是异步的。CefSharp 不知道这些setTimeout任务何时完成,因此提前返回。挂起的 javascript 代码最终会执行。要知道何时完成,您有几个选择:

  1. 通过完全摆脱来使您的异步 javascript 代码同步setTimeout
  2. 在您的异步 javascript 代码中设置一些全局变量,并定期在 C# 中检查您的网页以查看是否设置了该变量。
  3. 注册一些 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().


推荐阅读