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.pswp.cn/news/283863.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/283863.shtml
英文地址,請注明出處:http://en.pswp.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 …

第五周作業

本周作業內容&#xff1a;顯示當前系統上root、fedora或user1用戶的默認shell&#xff1b;#egrep "^(root|user1|fedora)" /etc/passwd|cut -d: -f72、找出/etc/rc.d/init.d/functions文件中某單詞后面跟一組小括號的行&#xff0c;形如&#xff1a;hello()&#xff…

我為什么卸載了今日頭條

曾經的自媒體人自述。 兩三年前自媒體熱曾席卷中國互聯網&#xff0c;當時短視頻還不是很火&#xff0c;一般的自媒體人都是以撰寫文章為主&#xff0c;各種微信公眾號層出不窮&#xff0c;10W的俗稱 爆文&#xff08;豹紋&#xff09;。后來以今日頭條為領頭的短視頻自媒體出現…

appium執行iOS測試腳本并發問題

appium1.4.XiOS9.Xxcode7.X: appium1.4.xiOS9.xxcode7.x&#xff0c;這一整套的配置做移動端自動化測試是測試人員常用的測試框架。關于&#xff0c;這一套測試框架的并發問題&#xff1a;基于mac端&#xff0c;啟動多臺appium服務器會導致appium的運行出錯。這是因為多個appiu…

WinForm(五)控件和它的成員

窗體無疑是WinForm的主角&#xff0c;每個窗體都是用一個class來承載&#xff0c;那么窗體的控件&#xff0c;就是類中的私有字段了。每個窗體有三個文件&#xff0c;兩個.cs文件&#xff0c;是一個分部類&#xff0c;Designer.cs是自動生成的C#代碼&#xff0c;一般是拖拽控件…

Atitit.異常處理 嵌套??冗長的解決方案

Atitit.異常處理 嵌套 冗長的解決方案 1. 異常處理的需要改進的地方1 2. 異常設計的初衷是, 在程序中出現錯誤時, 由程序自己處理錯誤, 盡量不要以exit(0)這種粗暴的方式中止程序. 1 3. 正常流程和異常流程的分離。2 4. “是藥三分毒”&#xff0c; 任何事物有缺點&#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…

linux IP、端口連通性測試

ssh -v -p 50001 root10.210.200.82轉載于:https://www.cnblogs.com/kuiyeit/p/6723508.html

緊急通知:360 網站衛士前端公共庫已停止服務

所有使用了360前端公共庫的開發者和站長們&#xff0c;請及時更換你的前端庫的鏈接&#xff08;主要是前端庫和谷歌 fonts&#xff09;&#xff0c;否則網站打開速度會極慢&#xff0c;甚至會在 Chrome 瀏覽器中崩潰。 360前端公共庫曾經提供的服務有&#xff1a; 前端公共庫&a…

一文學會Autofac的基礎操作:幾種實現注冊方式、3種注入方式、生命周期、AOP以及過濾器實現依賴注入...

前言&#xff1a;直接開干。使用Autofac進行服務注冊實踐&#xff1a;新建三個項目&#xff0c;分別是webapi項目 Wesky.Core.Autofac以及兩個類庫項目 Wesky.Core.Interface和Wesky.Core.Service。在Webapi項目下&#xff0c;引用Autofac的三個包&#xff1a;Autofac、Autofac…

解析互聯網廣告術語 CPM、CPC、CPA、CPS、CPL、CPR 是什么意思

1. CPM&#xff08;Cost per mille&#xff09;&#xff0c;每千次展現收費 這是一種最為常見的廣告模式&#xff0c;也是很多網站流量變現的一種途徑&#xff0c;這種廣告不管計算點擊&#xff0c;或者什么注冊下載之類的轉化&#xff0c;只要這個廣告在網站上被正常的展現給…

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…

解決ASP.NET Core在Task中使用IServiceProvider的問題

前言問題的起因是在幫同事解決遇到的一個問題&#xff0c;他的本意是在EF Core中為了解決避免多個線程使用同一個DbContext實例的問題。但是由于對Microsoft.Extensions.DependencyInjection體系的深度不是很了解&#xff0c;結果遇到了新的問題&#xff0c;當時整得我也有點蒙…

什么是SRE?一文詳解SRE運維體系

在任何有一定規模的企業內部&#xff0c;一旦推行起來整個SRE的運維模式&#xff0c;那么對于可觀測性系統的建設將變得尤為重要&#xff0c;而在整個可觀測性系統中。 可觀測性系統 在任何有一定規模的企業內部&#xff0c;一旦推行起來整個SRE的運維模式&#xff0c;那么對于…