之前开发的一个产品在上线后总有奇怪的BUG,经过一番调试后发现在使用CEF控件的
EvaluateScriptAsync
这个方法的时候,并不能保证成功.
经过一番查询,发现官方文档(https://github.com/cefsharp/CefSharp/wiki/General-Usage#devtools)有这么一段
2. How do you call a JavaScript method that returns a result?
If you need to evaluate code which returns a value, use the
Task<JavascriptResponse> EvaluateScriptAsync(string script, TimeSpan? timeout)
method. JavaScript code is executed asynchronously and as such uses the .NetTask
class to return a response, which contains error message, result and a success (bool
) flag.// Get Document Height var task = frame.EvaluateScriptAsync("(function() { var body = document.body, html = document.documentElement; return Math.max( body.scrollHeight, body.offsetHeight, html.clientHeight, html.scrollHeight, html.offsetHeight ); })();", null); task.ContinueWith(t => { if (!t.IsFaulted) { var response = t.Result; EvaluateJavaScriptResult = response.Success ? (response.Result ?? "null") : response.Message; } }, TaskScheduler.FromCurrentSynchronizationContext());For a more detailed example check out this Gist
Notes
- Scripts are executed at the frame level, and every page has at least one frame (
MainFrame
)- Only trivial values can be returned (like int, bool, string etc) - not a complex (user-defined) type which you have defined yourself. This is because there is no (easy) way to expose a random JavaScript object to the .NET world, at least not today. However, one possible technique is to turn the JavaScript object you wish to return to your .NET code into a JSON string with the JavaScript
JSON.toStringify()
method and return that string to your .NET code. Then you can decode that string into a .NET object with something like JSON.NET. See this MSDN link for more information. (https://msdn.microsoft.com/en-us/library/ie/cc836459(v=vs.94).aspx)
可以用这种方式获取到JS的返回值:
1 task.ContinueWith(t => 2 { 3 if (!t.IsFaulted) 4 { 5 var response = t.Result; 6 EvaluateJavaScriptResult = response.Success ? (response.Result ?? "null") : response.Message; 7 } 8 }, TaskScheduler.FromCurrentSynchronizationContext());
于是利用这一点,做了个"流水ID"
每次调用的时候就+1,另一头代码执行完后,返回该ID,如果调用失败(或者返回的ID无法识别),则重新发起,如果另一头收到连续两次一样的ID,则不做处理(但还是要返回ID的.).
这样个方法也能用来解决某些丢包问题.
时间: 2024-10-20 05:04:05