Blazor University (42)JavaScript 互操作 —— 生命周期和内存泄漏

原文链接:https://blazor-university.com/javascript-interop/calling-dotnet-from-javascript/lifetimes-and-memory-leaks/

生命周期和内存泄漏

源代码[1]

如果我们运行我们在从 Javascript 调用 .NET 中创建的应用程序并检查浏览器控制台窗口,我们会看到当我们导航到另一个页面时,JavaScript 仍在回调我们的组件。更糟糕的是,如果我们查看 Visual Studio 输出窗口,我们会看到我们的组件仍在被调用并输出从 JavaScript 传递的值,这意味着我们的组件还没有被垃圾回收!

当我们创建一个 DotNetObjectReference 时,Blazor 将生成一个唯一 ID(WASM 为整数,服务器端为 GUID)并在当前 JSRuntime 中存储对我们对象的查找。这意味着除非我们正确处理我们的引用,否则我们的应用程序将会泄漏内存。

DotNetObjectReference 类实现了 IDisposable。要解决我们的内存泄漏问题,我们需要执行以下操作:

  • 我们的组件应该保留对我们创建的 DotNetObjectReference 的引用。

  • 我们的组件应该实现 IDisposable 并释放我们的 DotNetObjectReference

@page "/"
@inject IJSRuntime JSRuntime
@implements IDisposable<h1>Text received</h1>
<ul>@foreach (string text in TextHistory){<li>@text</li>}
</ul>@code
{List<string> TextHistory = new List<string>();DotNetObjectReference<Index> ObjectReference;protected override async Task OnAfterRenderAsync(bool firstRender){await base.OnAfterRenderAsync(firstRender);if (firstRender){ObjectReference = DotNetObjectReference.Create(this);await JSRuntime.InvokeVoidAsync("BlazorUniversity.startRandomGenerator", ObjectReference);}}[JSInvokable("AddText")]public void AddTextToTextHistory(string text){TextHistory.Add(text.ToString());while (TextHistory.Count > 10)TextHistory.RemoveAt(0);StateHasChanged();System.Diagnostics.Debug.WriteLine("DotNet: Received " + text);}public void Dispose(){GC.SuppressFinalize(this);if (ObjectReference != null){//Now dispose our object reference so our component can be garbage collectedObjectReference.Dispose();}}
}
  • 第 3 行

    告诉编译器我们希望我们的组件实现 IDisposable

  • 第 16 行

    我们现在保留对 DotNetObjectReference 的引用。

  • 第 21 行

    如果这是我们的第一次渲染,我们创建一个 DotNetObjectReference 并将其传递给我们的 JavaScript 方法,以便它可以在生成新的随机数时回调我们。

  • 第 45 行

    当我们的组件被释放时,我们在 DotNetObjectReference 上调用 Dispose()

如果你还记得我们的 JavaScript 警告,我们不能过早调用 JavaScript,所以我们只在 OnAfterRender* 事件中使用 JSRuntime,并且只有在 firstRendertrue 时才使用。如果组件永远不会被渲染(例如,如果在服务器端 Blazor 应用程序中预渲染),那么我们的 DotNetObjectReference 将永远不会被创建,所以我们应该只在它不为 null 的情况下处理它。

警告:避免在已处理的 .NET 引用上调用方法

如果我们现在运行我们的应用程序,我们将看到我们的组件不再从 JavaScript 接收随机数。但是,如果我们查看浏览器的控制台窗口,我们会看到每秒都会出现一个错误。

c48f9f325d349ca4fe1802c1ff7af2cf.png

一旦我们的 DotNetObjectReference 被释放,它就会从 JSRuntime 中移除,从而允许我们的组件被垃圾回收——因此引用不再有效并且不应该被 JavaScript 使用。接下来,我们将调整我们的组件,使其取消 JavaScript setInterval,以便在我们的组件被销毁后不再执行它。

首先,我们需要更新我们的 JavaScript 以便它返回在我们执行 setInterval 时创建的句柄。然后我们需要添加一个附加函数,该函数将接受该句柄作为参数并取消间隔。

var BlazorUniversity = BlazorUniversity || {};
BlazorUniversity.startRandomGenerator = function (dotNetObject) {return setInterval(function () {let text = Math.random() * 1000;console.log("JS: Generated " + text);dotNetObject.invokeMethodAsync('AddText', text.toString());}, 1000);
};
BlazorUniversity.stopRandomGenerator = function (handle) {clearInterval(handle);
};
  • 第 3 行

    setInteval 创建的句柄从启动随机数生成器的函数返回。

  • 第 9 行

    一个函数,它将接受我们创建的间隔句柄并将其传递给 JavaScript clearInterval 函数。

最后,我们需要我们的组件跟踪我们创建的 JavaScript 区间的句柄,并在我们的组件被释放时调用新的 stopRandomGenerator 函数。

@page "/"
@inject IJSRuntime JSRuntime
@implements IDisposable<h1>Text received</h1>
<ul>@foreach (string text in TextHistory){<li>@text</li>}
</ul>@code
{List<string> TextHistory = new List<string>();int GeneratorHandle = -1;DotNetObjectReference<Index> ObjectReference;protected override async Task OnAfterRenderAsync(bool firstRender){await base.OnAfterRenderAsync(firstRender);if (firstRender){ObjectReference = DotNetObjectReference.Create(this);GeneratorHandle = await JSRuntime.InvokeAsync<int>("BlazorUniversity.startRandomGenerator", ObjectReference);}}[JSInvokable("AddText")]public void AddTextToTextHistory(string text){TextHistory.Add(text.ToString());while (TextHistory.Count > 10)TextHistory.RemoveAt(0);StateHasChanged();System.Diagnostics.Debug.WriteLine("DotNet: Received " + text);}public async void Dispose(){GC.SuppressFinalize(this);if (GeneratorHandle != -1){//Cancel our callback before disposing our object referenceawait JSRuntime.InvokeVoidAsync("BlazorUniversity.stopRandomGenerator", GeneratorHandle);}if (ObjectReference != null){//Now dispose our object reference so our component can be garbage collectedObjectReference.Dispose();}}
}
  • 第 16 行

    我们创建一个成员来保存对从 JavaScript BlazorUniversity.startRandomGenerator 函数返回的区间的引用。

  • 第 25 行

    我们将返回的句柄存储在我们的新成员中。

  • 第 46 行

    如果已设置句柄,我们将调用新的 JavaScript BlazoUniversity.stopRandomGenerator 函数,传递我们的区间句柄,以便将其传递给 clearInterval

Interval 在我们的 DotNetObjectReference 被释放之前被取消,因此我们的 JavaScript 不会尝试使用无效的对象引用调用 .NET 对象上的方法。根据良好的做法,我们在尝试清除之前检查 GeneratorHandle 成员是否已设置,以防在执行 OnAfterRender* 方法之前处理组件。

参考资料

[1]

源代码: https://github.com/mrpmorris/blazor-university/tree/master/src/JavaScriptInterop/CallingDotNetFromJavaScriptLifetimes

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/283863.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

深入浅出聊布隆过滤器(Bloom Filter)

之前在网上看到过这么一段话&#x1f447; Data structures are nothing different. They are like the bookshelves of your application where you can organize your data. Different data structures will give you different facility and benefits. To properly use the …

WinForm(五)控件和它的成员

窗体无疑是WinForm的主角&#xff0c;每个窗体都是用一个class来承载&#xff0c;那么窗体的控件&#xff0c;就是类中的私有字段了。每个窗体有三个文件&#xff0c;两个.cs文件&#xff0c;是一个分部类&#xff0c;Designer.cs是自动生成的C#代码&#xff0c;一般是拖拽控件…

一文详解|增长那些事儿

目录 增长的背景 1.1 增长的定义 1.2 如何判断事物是否在增长 1.3 如何判断事物能否持续增长 如何进行增长 2.1 寻找增长机会点&#xff08;人的能力&#xff09; 2.1.1 发散与收剑找机会点 2.1.2 实验分析验证 2.1.3 增长洞察提取策略 2.1.4 如何找到大机会 2.2 设…

在MVC项目中使用Ninject

项目结构图&#xff1a; App_start文件夹中的文件是VS自己创建的&#xff0c;其中NinjectWebCommon类在创建之初并不存在。后面会再次提到&#xff01; 添加一个Home控制器。代码如下&#xff1a; using EssentialTools.Models; using Ninject; using System; using System.Col…

一文学会Autofac的基础操作:几种实现注册方式、3种注入方式、生命周期、AOP以及过滤器实现依赖注入...

前言&#xff1a;直接开干。使用Autofac进行服务注册实践&#xff1a;新建三个项目&#xff0c;分别是webapi项目 Wesky.Core.Autofac以及两个类库项目 Wesky.Core.Interface和Wesky.Core.Service。在Webapi项目下&#xff0c;引用Autofac的三个包&#xff1a;Autofac、Autofac…

JavaScript数组迭代方法(图解)

转载于:https://www.cnblogs.com/seanna/p/6724032.html

Rider调试ASP.NET Core时报thread not gc-safe的解决方法

新建了一个ASP.NET Core 5.0的Web API项目&#xff0c;当使用断点调试Host.CreateDefaultBuilder(args)时&#xff0c;进入该函数后查看中间变量的值&#xff0c;报错Evaluation is not allowed: The thread is not at a GC-safe point。在群里问了也没人回应&#xff0c;可能没…

The SDK platform-tools version ((23)) is too old to check APIs compiled with API 26;

好像是更新过啥SDK之后&#xff0c;项目一直在包名的那一行显示红线&#xff0c;不过是不报编译错误的&#xff0c;就是看着老扎心老扎心的&#xff0c;开始以为是指定的SDK版本的问题&#xff0c;修改后发现无效&#xff0c;最后找到方法解决&#xff1a; 打开SDK Manager ---…

oracle 各种日期函数格式和操作

2019独角兽企业重金招聘Python工程师标准>>> ORACLE日期时间函数大全 TO_DATE格式(以时间:2007-11-02 13:45:25为例) Year: yy two digits 两位年 显示值:07 yyy three digits 三位年 显示值:00…

火山引擎李玉光:字节跳动大规模K8s集群管理实践

2022年5月31日&#xff0c;在CSDN云原生系列在线峰会第6期“K8s大规模应用和深度实践峰会”&#xff0c;火山引擎资深云原生架构师李玉光分享了《字节跳动大规模K8s集群管理实践》。 字节跳动云原生体系 字节跳动内部云原生技术的使用贯穿组织技术体系各层面&#xff0c;整体如…

(7)关于margin的一些想法2.0

这篇主要讨论的就是margin负值与float的关系。 首先&#xff0c;例子。 <!doctype html> <html> <head> <meta charset"utf-8"> <title>无标题文档</title> <style typetext/css> html,body{padding:0;margin:0;} div{wid…

什么是SRE?一文详解SRE运维体系

在任何有一定规模的企业内部&#xff0c;一旦推行起来整个SRE的运维模式&#xff0c;那么对于可观测性系统的建设将变得尤为重要&#xff0c;而在整个可观测性系统中。 可观测性系统 在任何有一定规模的企业内部&#xff0c;一旦推行起来整个SRE的运维模式&#xff0c;那么对于…

python初探

python近两年似乎已经很热了&#xff0c;不了解一下怎么能行呢&#xff0c;似乎python最大的优点就是简洁、易懂、优雅。目前豆瓣、知乎等后台服务使用的也都是python语言。 python一般可以用于网站服务、小工具、数据分析等工作。它作为高级语言&#xff0c;和js一样&#xff…

solr5.5索引mysql数据(新手总结)

一 solr5.5环境部署到Eclipse(luna版&#xff09; solr部署参见&#xff1a;http://blog.csdn.net/csmnjk/article/details/64121765 二 Ik分词器设置 IK分词器设置参见:http://blog.csdn.net/csmnjk/article/details/51693578 solr4版本的schema.xml文件对应solr5版本的manage…

老板加薪!看我做的WPF Loading!!!

老板加薪&#xff01;看我做的WPF Loading&#xff01;&#xff01;&#xff01;控件名&#xff1a;RingLoading作者&#xff1a;WPFDevelopersOrg原文链接&#xff1a; https://github.com/WPFDevelopersOrg/WPFDevelopers.Minimal框架使用大于等于.NET40&#xff1b;Visua…

如何避免下重复订单

电子交易的一个很基本的问题&#xff0c;就是避免用户下重复订单。用户明明想买一次&#xff0c;结果一看下了两个单。如果没有及时发现&#xff0c;就会带来额外的物流成本和扯皮。对商家的信誉也不好看。 从技术上看&#xff0c;这是一个分布式一致性问题&#xff1b;但实际…

图像分类学习笔记

1.计算机认识图像的方式&#xff1a;都是数字。例如一个 128X128 的3通道的图片 是由 128X128X3个数字 组成的。 2.面临的难点&#xff1a;一幅图可以说明。 3.分类器 A&#xff1a;Nearest Neighbor Classifier&#xff1a;与CNN无关&#xff0c;但是可以帮助我们理解一下分类…

知物由学 | 干货!一文了解安卓APP逆向分析与保护机制

“知物由学”是网易云易盾打造的一个品牌栏目&#xff0c;词语出自汉王充《论衡实知》。人&#xff0c;能力有高下之分&#xff0c;学习才知道事物的道理&#xff0c;而后才有智慧&#xff0c;不去求问就不会知道。“知物由学”希望通过一篇篇技术干货、趋势解读、人物思考和沉…

[转]以终为始,详细分析高考志愿该怎么填

为什么写这篇文章&#xff1f; 之所以写本文&#xff0c;是因为我自己有用处。 我简要介绍&#xff0c;长话短说。我从一个普通的211本科毕业&#xff0c;已经接受社会"毒打"多年&#xff0c;回想起高考填志愿&#xff0c;依然会觉得有些许遗憾。我在贵州省的一个小县…

ASP.NET Core 中的重定向

前言在《如何使用ASP.NET Core Web API实现短链接服务》中&#xff0c;我们使用了Redirect方法返回跳转状态码:[HttpGet("{shortUrl}")] public IActionResult GetUrl(string shortUrl) {var hashids new Hashids("公众号My IO", minHashLength: 6);var i…