Лучший / эффективный способ включить JavaScript при использовании пользовательских элементов управления - PullRequest
0 голосов
/ 04 декабря 2011

Я в .NET и всех связанных с этим интересных вещах, которые вы можете сделать, но мне интересно узнать об эффективности с пользовательскими элементами управления и JS.

Мои пользовательские элементы управления в основном состоят из страницы отображения ascx иКод .vb.ascx позади, как это принято в стиле кодирования с выделением кода в .NET, который отлично подходит для простоты кодирования, хотя он вдвое больше, чем требует требуемых файлов.Однако, насколько я понимаю, сервер компилирует их и эффективно возвращает HTML.

Там, где для элемента управления требуется JavaScript, в процессе разработки я делаю внешние файлы JS для каждого элемента управления с тем же именем,таким образом, пользовательские элементы управления состоят из 'controlName.ascx, controlName.vb.ascx, controlName.js'

Если страница, запрошенная пользователем, содержит несколько пользовательских элементов управления, браузер будет запрашивать несколько файлов JS, вероятно, masterфайл JS страницы, jQuery И каждый необходимый файл для соответствующих элементов управления.

Этот подход имеет смысл для меня во время разработки и, поскольку все хорошо и аккуратно, что позволяет легко решать проблемы, но когда он будет запущен, будет много запросов на получение из браузера, учитывая, что каждый разбраузер получает файл, даже процесс запроса файла на проверку того, кэширован ли он или нет, должен занять некоторое время.

Лучше бы я включил мой JS inline в файлы ascx, или код позади, непосредственно вставив скрипт, или каков "правильный" способ обработки этих нескольких файлов, чтобы уменьшить количество запросов от браузера.

Я использую спрайты CSS для кнопок и прочего по той же причине, поэтому мне интересно, что делать с файлами JS.В моем случае CSS обычно обрабатывается классами на основных страницах, поэтому это не проблема.

1 Ответ

0 голосов
/ 05 декабря 2011

Мы фактически создали элемент управления поверх ScriptManager, который автоматически извлекает все js из всех элементов управления на странице, включая scriptresource.axd, и сохраняет их в одном кэшированном файле.Это значительно улучшило производительность и сократило объем работ по техническому обслуживанию, поскольку оно автоматизировано.Мы создали это, начиная с .Net 2.0, поэтому я не уверен, что ScriptManager теперь предоставляет такую ​​же функциональность, но я подумал, что стоит упомянуть.

Вот наша реализация этого класса:

Option Explicit On
Option Strict On

Imports System.Collections.Generic
Imports System.Web.SessionState

Public Class OurScriptManager
    Inherits ScriptManager
    Implements IRequiresSessionState

    Private m_ScriptBuilder As New StringBuilder
    'Private m_sSessionIndex As String = ""
    Private m_cScripts As List(Of ScriptReference)
    Private m_fIsCached As Boolean
    Private m_sScriptName As String = ""
    Private m_sScriptFileName As String = ""

    Const CACHED_SCRIPTS_DIR As String = "/scriptcache/"

    Public Sub New()
        ' default constructor
    End Sub

    Public Property ScriptName() As String
        Get
            Return m_sScriptName
        End Get
        Set(ByVal value As String)
            m_sScriptName = value
        End Set
    End Property

    Private ReadOnly Property ScriptFileName() As String
        Get
            If String.IsNullOrEmpty(m_sScriptFileName) Then
                m_sScriptFileName = "~" & CACHED_SCRIPTS_DIR & Me.ScriptName & ".js"
            End If

            Return m_sScriptFileName
        End Get
    End Property

    Protected Overrides Sub OnInit(ByVal e As System.EventArgs)
        ' Exceptions are handled by the caller

        MyBase.OnInit(e)

        If String.IsNullOrEmpty(Me.ScriptName) Then
            Me.ScriptName = Me.Page.ToString
        End If

        ' this compiled script should be cached on the server
        ' check for the file, if it exists, load that file instead of generating it
        If Configuration.HasPageScriptBeenCached(Me.ScriptFileName) AndAlso File.Exists(Me.Page.Server.MapPath(Me.ScriptFileName)) Then
            m_fIsCached = True
        Else
            m_cScripts = New List(Of ScriptReference)
        End If
    End Sub

    Protected Overrides Sub OnResolveScriptReference(ByVal e As System.Web.UI.ScriptReferenceEventArgs)
        Try
            MyBase.OnResolveScriptReference(e)

            If Not m_fIsCached Then
                ' First, check to make sure this script should be loaded
                Dim fIsFound As Boolean

                For Each oXref As ScriptReference In m_cScripts
                    If oXref.Assembly = e.Script.Assembly AndAlso oXref.Name = e.Script.Name AndAlso oXref.Path = e.Script.Path Then
                        fIsFound = True
                        Exit For
                    End If
                Next

                ' If this script is found within the list of scripts that this page uses, add the script to the scripthandler.aspx js output
                If Not fIsFound Then
                    Dim oReference As ScriptReference
                    Dim oElement As ScriptReference
                    Dim fIsPathBased As Boolean

                    oElement = e.Script

                    If String.IsNullOrEmpty(oElement.Path) AndAlso Not String.IsNullOrEmpty(oElement.Name) AndAlso String.IsNullOrEmpty(oElement.Assembly) Then
                        ' If resource belongs to System.Web.Extensions.dll, it does not
                        ' provide assembly info that's why hard-coded assembly name is
                        ' written to get it in profiler
                        oElement.Assembly = "System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
                    End If

                    'check to see what type of script this is
                    If Not String.IsNullOrEmpty(oElement.Path) Then
                        ' this script is a physical file
                        oReference = New ScriptReference(oElement.Path)
                        fIsPathBased = True

                    ElseIf Not String.IsNullOrEmpty(oElement.Assembly) AndAlso Not String.IsNullOrEmpty(oElement.Name) Then
                        ' this script is generated by an assembly
                        oReference = New ScriptReference(oElement.Name, oElement.Assembly)

                    Else
                        ' Couldn't find script, so bail to allow standard processing to take place.
                        Return

                    End If

                    If Not fIsPathBased Then
                        Dim sUrl As String
                        Dim oRequest As HttpRequest
                        Dim sScriptResourcePath As String

                        sUrl = GetUrl(oReference)
                        sScriptResourcePath = String.Format("{0}{1}{2}{3}{4}{5}{6}{7}", Context.Request.Url.Scheme, "://", Context.Request.Url.Host, ":", Context.Request.Url.Port, "/", Context.Request.ApplicationPath, "/ScriptResource.axd")

                        oRequest = New HttpRequest("scriptresource.axd", sScriptResourcePath, sUrl.Substring(sUrl.IndexOf("?"c) + 1))

                        Try
                            Using oWriter As New StringWriter(m_ScriptBuilder)
                                Dim oHandler As IHttpHandler = New System.Web.Handlers.ScriptResourceHandler

                                oHandler.ProcessRequest(New HttpContext(oRequest, New HttpResponse(oWriter)))
                            End Using
                        Catch theException As Exception
                            Call ReportError(theException)
                            ' Since we couldn't automatically process this, just bail so that standard processing takes over
                            Return
                        End Try
                    Else
                        ' If this script is from a file, open the file and load the
                        ' contents of the file into the compiled js variable
                        Dim sAbsolutePath As String

                        sAbsolutePath = Context.Server.MapPath(oElement.Path)
                        Try
                            If System.IO.File.Exists(sAbsolutePath) Then
                                Using oReader As New StreamReader(sAbsolutePath, True)
                                    m_ScriptBuilder.Append(oReader.ReadToEnd())
                                End Using
                            Else
                                Throw New Exception("File " & sAbsolutePath & " does not exist")
                            End If
                        Catch theException As Exception
                            Call ReportError(theException, New ExtraErrorInformation("File", sAbsolutePath))
                            ' Since we couldn't automatically process this, just bail so that standard processing takes over
                            Return
                        End Try
                    End If

                    m_ScriptBuilder.AppendLine()

                    ' add this script to the script reference library
                    Dim oNewElement As New ScriptReference

                    oNewElement.Name = e.Script.Name.ToString()
                    oNewElement.Assembly = e.Script.Assembly.ToString()
                    oNewElement.Path = e.Script.Path.ToString()

                    m_cScripts.Add(oNewElement)
                End If
            End If

            ' a script filename is provided for caching
            e.Script.Assembly = String.Empty
            e.Script.Name = String.Empty
            e.Script.Path = Me.ScriptFileName
        Catch theException As Exception
            HttpContext.Current.Response.Write(ReportError(theException))
            HttpContext.Current.Response.End()
        End Try
    End Sub

    Protected Overrides Sub Render(ByVal writer As System.Web.UI.HtmlTextWriter)
        ' Exceptions are handled by the caller

        MyBase.Render(writer)

        If Not m_fIsCached Then
            If Not String.IsNullOrEmpty(Me.ScriptName) Then
                ' Save script to file for caching
                Using fsFile As New FileStream(Me.Page.Server.MapPath(Me.ScriptFileName), FileMode.Create, FileAccess.Write, FileShare.Read)
                    Using oWriter As New StreamWriter(fsFile)
                        oWriter.Write(m_ScriptBuilder.ToString)
                        oWriter.Flush()
                        oWriter.Close()
                    End Using
                    fsFile.Close()
                End Using

                ' Record that the script file has been cached
                Configuration.RecordPageScriptCached(Me.ScriptFileName)
            End If
            m_ScriptBuilder = Nothing
        End If
    End Sub

    Private Function GetUrl(ByVal oReference As ScriptReference) As String
        ' Exceptions are handled by the caller

        If String.IsNullOrEmpty(oReference.Path) Then
            Try
                Dim oMethod As MethodInfo

                oMethod = oReference.GetType.GetMethod("GetUrl", BindingFlags.NonPublic Or BindingFlags.Instance)
                If oMethod IsNot Nothing Then
                    Return DirectCast(oMethod.Invoke(oReference, New Object() {Me, False}), String)
                Else
                    Return String.Empty
                End If
            Catch ex As Exception
                Return String.Empty
            End Try
        Else
            Return Me.ResolveClientUrl(oReference.Path)
        End If
    End Function

End Class

В приведенном выше коде ReportError записывает исключение в журнал событий и / или файл;Вы можете заменить это своим собственным механизмом.

Вот код конфигурации:

Private Shared m_cCachedPageScripts As Collections.Generic.List(Of String)

''' <summary>
''' This method is used to determine whether or not the script for the page has been cached. 
''' This is used for script combining.
''' </summary>
''' <param name="sKey"></param>
''' <returns></returns>
''' <remarks></remarks>
Public Shared Function HasPageScriptBeenCached(ByVal sKey As String) As Boolean
    ' Exceptions are handled by the caller

    SyncLock CacheSyncObject
        If m_cCachedPageScripts IsNot Nothing AndAlso m_cCachedPageScripts.Contains(sKey) Then
            Return True
        End If
    End SyncLock

End Function
''' <summary>
''' This method is used to record the fact that the page script has been cached.
''' This is used for script combining.
''' </summary>
''' <param name="sKey"></param>
''' <remarks></remarks>
Public Shared Sub RecordPageScriptCached(ByVal sKey As String)
    ' Exceptions are handled by the caller

    SyncLock CacheSyncObject
        If m_cCachedPageScripts Is Nothing Then
            m_cCachedPageScripts.Add(sKey)
        End If
        m_cCachedPageScripts.Add(sKey)
    End SyncLock
End Sub
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...