EvaluateScriptAsync挂起

EvaluateScriptAsync hanging

在 CefSharp WinForms 中,我试图在页面加载后使用 JS 获取页面的 html 源,但是应用程序冻结了。我使用的是BackgroundWorker,相关功能如下:

void bw_DoWork(object sender, DoWorkEventArgs e)
{
    browser.Load("http://www.google.com");

    browser.FrameLoadEnd += delegate
    {
        object js = EvaluateScript(browser, "1+1");
        MessageBox.Show(js.ToString());
    };
}

object EvaluateScript(ChromiumWebBrowser b, string script)
{
    var task = b.EvaluateScriptAsync(script);
    task.Wait();
    return task.Result;
}

虽然您在 BackgroundWorker 线程中分配 FrameLoadEnd,但它实际上是在底层 CEF UI 线程上执行的,因此您无法在没有问题的情况下阻止它。

我通常建议您从事件处理程序中生成一个 Task 来完成您的工作。

正如 amaitland 所指出的,FrameLoadEnd 导致 UI 线程中的 运行 挂起。以下代码有效:

void bw_DoWork(object sender, DoWorkEventArgs e)
{
    first.Load("http://www.google.com");

    browser.FrameLoadEnd += delegate
    {
        Task task = new Task(() => {
            object js = EvaluateScript(browser, "document.getElementsByTagName('html')[0].innerHTML;");
            MessageBox.Show(js.ToString());
        });
        task.Start();
    };
}

static object EvaluateScript(ChromiumWebBrowser b, string script)
{
    var task = b.EvaluateScriptAsync(script);
    task.Wait();
    JavascriptResponse response = task.Result;
    return response.Success ? (response.Result ?? "") : response.Message;
}

作为一般规则,在异步代码上使用 Task.Wait 是个坏主意;相反,你应该 use async "all the way down". See also Don't Block on Async Code by Stephen Cleary。简短的回答是,如果您在具有同步上下文的应用程序中执行此操作,您可能会导致循环等待同步上下文(并因此导致死锁)。我链接到的文章有几个这样的例子,但我强烈建议如果可能的话在这里用await替换Task.Wait