3

ダイナミクスが多くのチェックボックス (700 以上) を生成するフォームがあります。IE ではフォームの読み込みが非常に遅く (Chrome ではほとんど読み込まれません)、フォームを投稿すると Web ブラウザーがほとんどロックされます。

どうすればこれをデバッグできますか、またはこのパフォーマンスの問題を引き起こしている何か間違ったことをしていますか? それとも、これは巨大なフォームで予想されるので、それを分割しようとする必要があります.

これが私のコントローラーです:

public ActionResult Create(int id)
    { 
            var model = new TaskRequestViewModel
                {
                    Task = new Task(),
                    Components = db.Component.ToList()
                       …. 
                 }
            return View(model);           
    }

私のモデルを簡単に説明すると、約 10 個のコンポーネントがあり、各コンポーネントには約 10 個のサブコンポーネントがあり、各サブコンポーネントには約 10 個のオプション (チェックボックス) があります。その結果、前述の700以上のフィールド(およびいくつかの非表示フィールド)が生成されます。チェックボックスが少ない場合(100程度)は問題なく動作しました。

私の見解は次のようなものです(3つのネストされたループがあります):

           @for (int cI = 0; cI < Model.Components.Count; cI++)
           {  
                    @Html.HiddenFor(x => Model.Components[cI].ComponentId)  

                    @for (int scI = 0; scI < Model.Components[cI].SubComponents.Count; scI++)
                    { 
                            @Html.DisplayFor(x => Model.Components[cI].SubComponents[scI].Name)                                 
                            @Html.HiddenFor(x => Model.Components[cI].SubComponents[scI].SubComponentId)

                            @for (int t = 0; t < Model.Components[cI].SubComponents[scI].TaskTypes.Count; t++)
                            {
                                @Html.HiddenFor(x => Model.Components[cI].SubComponents[scI].TaskTypes[t].SubComponentTaskTypeId)
                                @Html.HiddenFor(x => Model.Components[cI].SubComponents[scI].TaskTypes[t].TaskTypeId)
                                @Html.CheckBoxFor(x => Model.Components[cI].SubComponents[scI].TaskTypes[t].Active)
                           } 

                    }

          }
4

4 に答える 4

6

もう 1 つ気をつけなければならないのは、クライアント側の検証を使用する場合の Html.HiddenFor です。

MVC プロジェクトに同梱されているデフォルトのバンドルを使用してjquery.validate.unobtrusive.jsを使用している場合、次のようなスクリプト レンダーを使用します。

@Scripts.Render("~/bundles/jqueryval")

(注: 名前を変更した可能性があります。これがデフォルトです)

これがあると、Html.HiddenFor は次のようにレンダリングされます。

<input data-val="true" data-val-required="The XYZ field is required." name="XYZ" type="hidden" value="">

言うまでもなく、これらのフィールドではクライアント側の検証を有効にする必要はありません。ユーザーはそれらを見ることも操作することもできず、常にモデルによって埋められるべきです。

これを回避する方法は非常に簡単です。

@Html.HiddenFor(x => x.XYZ, new { data_val = "false" })

クライアント側の検証が必要ない場合は、バンドルが含まれていないことを確認してください。

詳細については、こちらをご覧ください。

于 2014-08-28T11:03:12.017 に答える
5

Visual Studio パフォーマンス アナライザーを使用すると、インデックス アクセサーの第 2 レベルまでに、レンダリング時間が大幅に短縮されることがわかります。HiddenFor、EditorFor、LabelFor などの拡張機能は、HTML の生成中にモデルに反映されて ID、名前、およびデータ注釈の存在を判断するため、非常に強力になる可能性があります。

レンダリングに非常に時間がかかるため、一部の HTML を取得し始めたときにブラウザーがフリーズする傾向がありますが、すべてを取得していないため一時停止します。すべての HTML がロードされた後でも、ロード時に実行しようとする JavaScript ライブラリを評価する必要があります (潜在的に多くのフィールドにわたって - これはビジネス ロジックによって異なります。Modernizr、Html5Shi[v|m]、など)控えめな検証を使用している場合に送信すると、各フィールドが列挙され、検証と OnSubmit タイプのロジックがチェックされるため、フリーズする可能性があります。

レンダリングを高速化するには:

モデルが複数レベルの子を使用する場合、この実行は多くのレコードで非常にコストがかかります。残念ながら、各レベルを独自の部分ビューに移動して親コレクションを渡すだけでは、問題は 100% 解決されません。速度は向上しますが、モデル名が正しく生成されなくなります。

たとえば、子の 1 つの入力タグの Name 属性は、コンテキストの完全なチェーンを持つモデルに基づいて、「Components[17].SubComponents[33].TaskTypes[5].SubComponentTaskTypeId」のようになります。部分ビューに分割し、モデルを TaskType として指定した場合、18 番目のコンポーネントの 34 番目のサブコンポーネントで 6 番目のものをレンダリングしようとすると、名前は「TaskType.SubComponentTaskTypeId」になります (モデルが TaskType で呼び出されたと仮定します)ループ) または "TaskType[5].SubComponentTaskTypeId" (モデルが一度呼び出された IEnumerable であると仮定します)。

これは、モデル バインダーが、送信されたフォームを完全なオブジェクトに戻す方法を認識できなくなることを意味します。

私たちはこの問題を Editor Templates で解決しました。これらは基本的に部分的なビューですが、親のコンテキストは、フィールド名の前に自動的に追加される Prefix プロパティとして保存されます。パフォーマンスが少し向上し (多くのフィールドを実行している場合は、まだ優れているわけではありません)、アクションに投稿するときにモデル バインダーが理解できる方法で名前が生成されます。

プロパティにエディター テンプレートを使用する場合は、

@for (int t = 0; t < Model.Components[cI].SubComponents[scI].TaskTypes.Count; t++)
{
    @Html.EditorFor(m => m.TaskType[t])
}

それ自体が、Components[m] から呼び出されたエディター テンプレートである SubComponents[n] から呼び出されたエディター テンプレートにある場合は、完全な名前解決を維持します。これは、各レベルが Prefix を 1 回取得し、子をレンダリングするときにそれを保存するため、モデルを繰り返し反映して名前を生成する必要がなくなるためです。

おまけとして、ビューが少し読みやすくなり、表示ロジックが混在するのではなく、懸念事項 (データ型) によって分離されるようになりました。

送信時のフリーズを診断するには:

何がいつ実行されているかを確認するには、いくつかの JavaScript パフォーマンス アナライザーを実行する必要があります。どのライブラリがロードされているかを見て、それらが必要かどうかを確認してください。バンドルと _layout に Modernizr へのデフォルトの MVC 参照がある場合は、そこから大きな打撃を受けています。デバッグのこの部分は、使用されているクライアント ライブラリに依存するため、ガイドするのが困難です。

編集:このような状況 (行ごとにテキストボックス、3 つの入力、3 つのリンク、および 5 つのラベルを持つ 3 つのレベルの子の行が多数ある) を持っている同僚と話している間、彼はまだ持っていた特定のユーザーの非常に多くのレコードをレンダリングすることに問題がありました。報告する行数が異常に多い。データが多すぎてブラウザが不安定になり、クラッシュすることもありました。

彼は最終的に JavaScript レンダリング テンプレートを使用して問題を解決しました。基本的に、彼は展開リンクとともに各行の親をロードしました。それをクリックすると、AJAX を使用して子の JSON オブジェクトを取得し、レンダリング テンプレートを使用して HTML を生成します。もちろん、モデル バインダーが送信時にそれらを取得できるように id 属性と name 属性を正しく設定するように注意する必要がありますが、1 つの親に非常に多くの行があり、オンデマンドでレンダリングする際に問題が発生することはなかったので、彼にとってははるかに優れていました。 . 私たちのビジネス ロジックでは、チェックボックスが基本的に単一の親からその子までのチェーンとして動作し、親全体では動作しなかったため、これが可能になりました。つまり、ユーザーが作業を行ったり、変更を送信したりしようとしたときに、すべての親が完全にロードされていなくても問題ありませんでした。

于 2013-08-01T21:23:25.910 に答える