WebAssembly项目中如何同步调用JS模块的JsInterop方法?
如何在Blazor WebAssembly中同步导入并调用JS模块?
原异步实现代码
之前使用异步IJSRuntime加载JS模块并调用函数的代码如下:
模块初始化
private readonly Lazy<Task<IJSObjectReference>> moduleTask; public LocalJsInterop(IJSRuntime jsRuntime) { moduleTask = new(() => jsRuntime.InvokeAsync<IJSObjectReference>( "import", "./../_content/WebPlayerControls/localJsInterop.js").AsTask()); }
异步调用函数
public async ValueTask<string> GetWindowLocation() { var module = await moduleTask.Value; string value = await module.InvokeAsync<string>("GetWindowLocation"); return value; }
遇到的问题
尝试改用IJSInProcessRuntime实现同步调用时,遇到以下问题:
- 直接用
jsRuntime.Invoke<IJSObjectReference>("import", ...)加载模块后,只能调用异步的InvokeAsync<>,无法使用同步Invoke<> - 尝试使用
IJSInProcessObjectReference初始化模块时,执行InvokeVoid会卡住;改用InvokeVoidAsync则抛出“未找到函数”异常,代码如下:
private readonly Lazy<IJSInProcessObjectReference> moduleTask; public LocalJsInterop(IJSInProcessRuntime jsRuntime) { moduleTask = new(() => jsRuntime.Invoke<IJSInProcessObjectReference>( "import", "./../_content/WebPlayerControls/localJsInterop.js")); m_jsRuntime = jsRuntime; } public void ShowMessage() { var module = moduleTask.Value; module.InvokeVoid("ShowMessage"); }
解决方案
ES模块的import本身是异步API,没有同步版本,因此必须先异步完成模块加载,再基于已加载的模块进行同步调用。具体实现步骤如下:
修正后的模块初始化
使用Lazy<Task<IJSInProcessObjectReference>>延迟异步加载模块,并将加载后的IJSObjectReference转换为IJSInProcessObjectReference:
private readonly Lazy<Task<IJSInProcessObjectReference>> _moduleTask; private readonly IJSInProcessRuntime _jsRuntime; public LocalJsInterop(IJSInProcessRuntime jsRuntime) { _jsRuntime = jsRuntime; _moduleTask = new Lazy<Task<IJSInProcessObjectReference>>(async () => { // 异步导入ES模块 var jsObjectRef = await _jsRuntime.InvokeAsync<IJSObjectReference>( "import", "./../_content/WebPlayerControls/localJsInterop.js"); // 转换为进程内对象引用,支持同步调用 return jsObjectRef as IJSInProcessObjectReference; }); }
同步调用函数
通过GetAwaiter().GetResult()同步等待模块加载完成,之后使用同步方法调用JS函数:
public void ShowMessage() { var module = _moduleTask.Value.GetAwaiter().GetResult(); module.InvokeVoid("ShowMessage"); } public string GetWindowLocation() { var module = _moduleTask.Value.GetAwaiter().GetResult(); return module.Invoke<string>("GetWindowLocation"); }
注意事项
- JS模块导出格式:确保
localJsInterop.js中的函数正确导出,示例如下:
export function ShowMessage() { alert("同步调用JS模块函数"); } export function GetWindowLocation() { return window.location.href; }
- 路径正确性:确认模块路径
./../_content/WebPlayerControls/localJsInterop.js指向正确的静态资源位置,Blazor WebAssembly中需确保资源已正确嵌入或发布。
内容的提问来源于stack exchange,提问作者Anarkhys
相关产品推荐
相关产品推荐

