Blazor Server偶发$ is not a function错误排查求助
Blazor Server 偶发
window.$ is not a function 错误排查与修复 问题表现
- 应用2月上线后偶发JS互操作异常,本地开发、测试、预发布、生产环境均无法稳定复现,异常触发时会中断用户当前操作,影响使用体验
- 异常触发点为组件
OnAfterRenderAsync生命周期内,调用IJsRuntime.Invoke*Async系列方法执行JS互操作时抛出,核心错误堆栈如下:
Microsoft.JSInterop.JSException: window.$ is not a function TypeError: window.$ is not a function at Module.NewDocumentElement (https://<site>/_content/DragonSpark.Presentation//Environment/Browser/Document/DocumentElement.js:11:43) at https://<site>/_framework/blazor.server.js:1:3501 at new Promise (<anonymous>) at kt.beginInvokeJSFromDotNet (https://<site>/_framework/blazor.server.js:1:3475) at https://<site>/_framework/blazor.server.js:1:72001 at Array.forEach (<anonymous>) at kt._invokeClientMethod (https://<site>/_framework/blazor.server.js:1:71987) at kt._processIncomingData (https://<site>/_framework/blazor.server.js:1:70029) at vt.connection.onreceive (https://<site>/_framework/blazor.server.js:1:64432) at WebSocket.o.onmessage (https://<site>/_framework/blazor.server.js:1:48766) at async ValueTask<TValue> Microsoft.JSInterop.JSRuntime.InvokeAsync<TValue>(long targetInstanceId, string identifier, object[] args) at async ValueTask<TOut> DragonSpark.Model.Operations.SelectingResult<TIn, TOut>.Get() in D:/a/1/s/Framework/DragonSpark/Model/Operations/SelectingResult.cs:line 23 at async ValueTask<TOut> DragonSpark.Model.Operations.OperationResulting<TIn, TOut>.Get() in D:/a/1/s/Framework/DragonSpark/Model/Operations/OperationResulting.cs:line 30 at async Task DragonSpark.Presentation.Components.Dialogs.DialogClassMonitor.OnAfterRenderAsync(bool firstRender) in D:/a/1/s/Framework/DragonSpark.Presentation/Components/Dialogs/DialogClassMonitor.razor:line 39
- 已尝试将jQuery等CDN脚本从head标签移动到body标签底部,问题仍偶发。当前页面初始脚本结构中jQuery为第一个加载的第三方脚本。
核心排查方向
这类低概率、无法稳定复现的脚本加载时序问题,不要默认“脚本写在前面就一定会先加载完成”,重点排查以下几个场景:
- 预渲染时序冲突:如果
_Host.cshtml中开启了prerender="true",静态页面输出阶段不会建立Blazor电路,电路首次连通触发OnAfterRenderAsync的极端场景下,用户侧网络波动可能导致CDN脚本尚未完成解析执行 - CDN可用性问题:运营商劫持、CDN边缘节点故障、用户弱网环境都可能导致jQuery脚本加载超时、加载失败,和脚本标签放置位置无关
- 全局变量污染:第三方组件、自定义脚本如果存在重置
window.$变量的逻辑,极端加载时序下会覆盖jQuery挂载的全局方法 - 电路重连异常:用户网络临时波动触发Blazor电路自动重连时,会重新触发生命周期方法,如果此时页面存在动态脚本替换逻辑,可能导致jQuery实例被销毁
可落地修复方案
- 不要依赖脚本标签顺序保证依赖就绪,增加JS侧加载校验
所有依赖jQuery的互操作方法,执行前先检测jQuery是否可用,等待加载完成再执行业务逻辑,从根源上规避时序问题,参考实现:// 挂载到全局的jQuery就绪检测方法 window.ensureJQueryReady = () => { return new Promise((resolve) => { const checkReady = () => window.$ && typeof window.$ === 'function' ? resolve(true) : setTimeout(checkReady, 50); checkReady(); }); } // 改造原有业务方法,前置就绪检测 window.NewDocumentElement = async () => { await ensureJQueryReady(); // 原有依赖jQuery的业务逻辑 } - 增加CDN加载兜底逻辑
在jQuery的CDN脚本标签后增加失败检测,CDN加载失败时自动加载站点本地存储的jQuery副本,避免CDN不可用导致的全局错误:<script src="https://code.jquery.com/jquery-3.5.1.min.js" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script> <script> window.$ || document.write('<script src="/js/jquery-3.5.1.min.js"><\/script>'); </script> - 规避全局$变量冲突
所有自定义JS逻辑中,优先使用jQuery全称调用,或通过闭包隔离$变量作用域,避免其他脚本覆盖全局$导致的异常:(function($) { // 闭包内可安全使用$,不受全局变量污染影响 // 业务逻辑 })(jQuery); - 优化生命周期执行逻辑
依赖jQuery的初始化逻辑仅在firstRender === true时执行一次,避免电路重连时重复初始化引发冲突;同时可增加1-2次短延迟重试,覆盖极端网络延迟场景。
内容的提问来源于stack exchange,提问作者Mike-E
相关产品推荐
相关产品推荐

