2011年1月20日,星期四

消除大型JS双色球推荐一注以优化SharePoint 2010 Internet网站

回到SharePoint 2007的时间框架,我写道 我的清单,用于优化SharePoint网站 –这是来自各种来源(本文引用)以及为客户诊断性能问题的知识的汇总,’仍然是我最受欢迎的职位之一。几乎所有建议仍然适用于SP 2010,并且核心提示(如输出缓存,BLOB缓存,IIS压缩等)可能会对您的网站速度产生巨大影响。那些开发SharePoint网站的人可能还记得,抑制大型JavaScript双色球推荐一注(例如core.js)是另一个关键步骤,因为SharePoint 2007将这些双色球推荐一注添加到了每个页面中,即使对于匿名用户也是如此。这意味着‘page weight’SharePoint页面的性能非常差,每次页面加载时都会有大量数据通过网络传输。由于匿名用户没有这样做,这使得SharePoint Internet网站的运行速度比他们需要的慢。’t actually 需要 core.js(因为它促进了通常只有经过身份验证的用户才需要的编辑功能),实际上,Microsoft使用自定义代码发布了一种解决方法 这里.

SP2010问题

为了缓解此问题,SharePoint 2010引入了按需脚本框架(SOD) –它旨在仅发送实际需要的JavaScript双色球推荐一注,并且在许多情况下,页面加载完成后可以在后台加载它们。此外,JavaScript双色球推荐一注本身也已缩小,因此要小得多。听起来不错。但是,以我的经验来看’不能完全解决问题,并且有很多变量,例如开发人员如何引用JavaScript双色球推荐一注。一世’我猜这是您的里程可能会变化的领域,但肯定是我目前的雇主’s site (www.contentandcode.com)我们担心SP2010仍在为匿名用户添加一些沉重的JS双色球推荐一注,尽管显然是由于SOD而在页面加载之后添加了一些。一些较大的双色球推荐一注用于功能区功能,这似乎很疯狂,因为我们的网站没有’t even 采用 匿名用户的功能区。一世’现在已经多次被问到这个问题,所以显然其他人也有同样的担忧。 瓦尔德克 对于这个问题,也有一个很棒的解决方案,其中包括为经过身份验证/匿名的用户创建两组母版页/页面布局,但是  that wasn’在我们的情况下是一个选择。

 N.B.请记住,我们主要是在讨论“first-time”这里的用户体验–在随后的页面加载中,双色球推荐一注将被浏览器缓存。但是,在互联网站点上’s the 第一次 experience that we tend to care a lot about!

When I 采用 Firebug, I can see that no less than 480KB of JavaScript 是 being 加载ed, with an overall 页面重量 of 888KB (and consider that, although this 大量图片的网站, 图像的精灵图 等等。):

时间轴不带脚本2

如果我们有办法完全禁止匿名用户使用某些较大的双色球推荐一注,那么我们’d have 123KB of JavaScript with an overall 页面重量 of 478.5KB (70% of it now being the 图片s):

TimelineWithScriptsSuppressed2

But what about page 加载 times?

现在,如果你’我一直在注意你应该说 “但是克里斯,由于脚本随需应变,这些双色球推荐一注无论如何都应该在UI之后加载,那么谁在乎呢?用户赢了’t notice!”. 那’这也是我的想法。但是,这并没有’进行测量时似乎加起来了。我想了很长时间,用哪种工具来衡量– I decided to 采用 锤头,由知名的网络性能专家开发的工具 史蒂夫·索德斯 Google的使用Hammerhead,您可以轻松访问网站10次,然后平均结果。作为旁注,Hammerhead和Firebug确实保证记录相同的页面加载时间– if you’我曾经在Firebug中想过这个’是我们关注的Firebug中的红线。 Mozilla文档 将蓝线和红线(如上面的屏幕截图所示)定义为:

  • 蓝色= DOMContentLoaded。当页面的DOM准备就绪,但是引用的样式表,图像和子帧可能未完成加载时触发。
  • 红色=负载。使用“load”事件,以检测页面已满。

Additionally, 锤头 conveniently simulates 第一次 site visitors (“Empty cache”)和回访者(“Primed cache”) - I’m主要关注第一类。这是我记录的页面加载时间:

在不禁止大型JS双色球推荐一注的情况下:

图片

禁止显示较大的JS双色球推荐一注:

PageLoadStats_Suppressed

Reading into the page 加载 times

简要统计转移-我建议我们考虑 比较时的中位数和平均值(算术平均值),以防您不同意我的逻辑。我个人认为我们可以使用平均值,因为我们可能会有异常值,但这’相当代表任何服务器’s workload. 无论如何,根据我的数学,新访客的差异(使用两种方法)是:

  • 中位数–抑制JS速度提高16%
  • 平均–抑制JS速度提高24%

无论哪种方式,我’我一定会把它做一个优化。我们’ve还减少了后续页面加载的负担,这很不错。

接下来要考虑的是网络延迟。测试是在我的开发VM上本地执行的–这意味着就用户和服务器之间的地理距离而言,’s大约为0.0米,如果您希望保留小数点后3位,则为0.000。除非您的全球网站访问者恰好驻留在您的服务器机房中,否则现实情况显然是‘worse’意味着收益可能大于我的统计数据所暗示的收益。如果您的站点的访问者位于服务器的其他大洲,或者用户的连接速度较慢,则尤其如此– in these cases, 页面重量 是 accepted to be an even bigger factor in site performance than usual.

如何’s done

我采取的方法是防止SharePoint首先将不必要的JS双色球推荐一注添加到页面。这实际上很棘手,因为脚本引用可以源自任何地方(用户控件,Web部件,委托控件等)。–但是,SharePoint通常使用以下方式添加大型JS双色球推荐一注: ClientScriptManager 要么 脚本链接 控制和两者都以相同的方式工作。页面上的控件会在页面初始化周期(早期)中注册所需的JS双色球推荐一注,然后在预渲染阶段(后期)将各个链接添加到页面中。因为我知道有些双色球推荐一注’t实际需要,我们可以简单地从集合中删除注册(它’呈现之前的HttpContext.Current.Items中的s)–这是通过母版页中的控件完成的。坏消息是代码中需要进行一些反射(读取而不是写入),但是坦率地说,我们’如果这意味着一个更快的网站,那就可以了。如果你’对细节感兴趣,它’s because it’不是存储在HttpContext.Current.Items中的字符串的集合,而是Microsoft.SharePoint.WebControls.ScriptLinkInfo对象(内部)。

控件参考(请注意,要抑制的双色球推荐一注是可配置的):

<!-- the SuppressScriptsForAnonymous control MUST go before the 脚本链接 control in the master page -->
<COB:SuppressScriptsForAnonymous runat="server" FilesToSuppress="cui.js;core.js;SP.Ribbon.js" />
<SharePoint:ScriptLink language="javascript" Defer="true" OnDemand="true" runat="server"/> 

编码:

using System;
usingSystem.Collections;
using System.Collections.Generic;
using System.Reflection;
using System.Web;
using System.Web.UI;
 
namespace COB.SharePoint.WebControls
{
    /// <summary>
    /// Ensures anonymous 采用rs of a SharePoint 2010 site do not receive unnecessary large JavaScript files (slows down first page 加载). Files to suppress are specified 
    /// in the FilesToSuppress property (a semi-colon separated list). This control *must* be placed before the main OOTB 脚本链接 control (Microsoft.SharePoint.WebControls.ScriptLink) in the 
    /// markup for the master page.
    /// </summary>
    /// <remarks>
    /// This control works by manipulating the HttpContext.Current.Items key which contains the script links added by various server-side registrations. Since SharePoint 采用s sealed/internal 
    /// code to manage this list, some minor reflection 是 required to read values. However, this 是 preferable to end-users downloading huge JS files which they do not 需要.
    /// </remarks>
    [ToolboxData("<{0}:SuppressScriptsForAnonymous runat=\"server\" />")]
    public class SuppressScriptsForAnonymous : Control
    {
        private const string HTTPCONTEXT_SCRIPTLINKS = "sp-scriptlinks";
        private List<string> files = new List<string>();
        private List<int> indiciesOfFilesToBeRemoved = new List<int>();
 
        public string FilesToSuppress
        {
            get;
            set;
        }
        
        protected override void OnInit(EventArgs e)
        {
            files.AddRange(FilesToSuppress.Split(';'));
 
            base.OnInit(e);
        }
 
        protected override void OnPreRender(EventArgs e)
        {
            // only process if 采用r 是 anonymous..
            if (!HttpContext.Current.User.Identity.IsAuthenticated)
            {
                // get list of registered script files which will be 加载ed..
                object oFiles = HttpContext.Current.Items[HTTPCONTEXT_SCRIPTLINKS];
                IList registeredFiles = (IList)oFiles;
                int i = 0;
 
                foreach (var file in registeredFiles)
                {
                    // 采用 reflection to get the 脚本链接Info.Filename property, then check if in FilesToSuppress list and remove from collection if so..
                    Type t = file.GetType();
                    PropertyInfo prop = t.GetProperty("Filename");
                    if (prop != null)
                    {
                        string filename = prop.GetValue(file, null).ToString();
 
                        if (!string.IsNullOrEmpty(files.Find(delegate(string sFound)
                        {
                            return filename.ToLower().Contains(sFound.ToLower());
                        })))
                        {
                            indiciesOfFilesToBeRemoved.Add(i);
                        }
                    }
 
                    i++;
                }
 
                int iRemoved = 0;
                foreach (int j in indiciesOfFilesToBeRemoved)
                {
                    registeredFiles.RemoveAt(j - iRemoved);
                    iRemoved++;
                }
 
                // overwrite cached value with amended collection.. 
                HttpContext.Current.Items[HTTPCONTEXT_SCRIPTLINKS] = registeredFiles;
            }
            
            base.OnPreRender(e);
        }
    }
}

使用注意事项

对我们来说,这是一个完全可以接受的解决方案。它’很难说是否会正式支持这种方法,但是添加一个“disable”切换到可能减轻对支持电话的担忧。最终,它没有’对我来说,这与2007年时间表中使用的方法感觉不太一样,但是在任何情况下,这都是每个部署的实施决策,可能并不适合所有部署。有趣的是,我’以前曾与一些人共享过此代码,最后我听说它可能会在运行SP2010的高流量* .microsoft.com网站上使用,所以让我听到这些人也都很好也很有趣。

此外,您需要考虑您的网站是否使用了我们提供的任何JavaScript’重新试图压制。例如,SharePoint 2010’的模式对话框,状态/通知栏或客户端OM等。

最后,通过调整双色球推荐一注进行抑制(例如某些站点可能不需要init.js),并扩展控件以处理CSS双色球推荐一注,可能会获得更好的结果。即使你曾经’为此,请测试,测试,测试。

概要

Although there are many ways to optimize SharePoint internet sites, dealing with 页面重量 是 a key step and in SharePoint much of it 是 caused by JavaScript files which are usually unnecessary for anonymous 采用rs. Compression can certainly help 这里, but comes with a trade-off of additional server 加载, and it’很难计算出载荷/收益以达到正确的压缩水平。在我看来,如果我们关心性能,最好首先不要将那些不必要的双色球推荐一注首先发送到管道中,’是我的方法去的地方。一世’d如果您认为我的测试或分析有任何缺陷,希望能收到您的来信,因为对我来说最终的好结果就是发现它’一个没有的问题’真的需要解决,这样整个问题才能解决!

16条评论:

马里奥·科尔特斯·弗洛雷斯(MarioCortésFlores)说过...

做得好!!!

杰夫说过...

尼斯写克里斯!感谢您提供有关节省速度以及解决方案如何工作的详细信息。很有意思。

本尼迪克特·阿方斯(Benedict Alphonse)说过...

好贴。克里斯。为开发活动增值。

公斤 said...

出色的工作,出色的职位。

未知说过...

优秀的帖子!
如果我们重新添加init.js,它会添加我们可能已排除的所有JS双色球推荐一注,因为它对所有其他JS双色球推荐一注都有参考意义。

删除JS双色球推荐一注后,表单提交停止工作,并且在页面上出现了JS错误,我们使用OTB内容编辑器Webpart来显示静态内容。为了解决这个问题,我们创建了另一个母版页,其中没有排除任何JS双色球推荐一注,并且它可以工作。但是我们必须测试测试和测试。

您能建议一下这些JS双色球推荐一注的依赖性吗?

克里斯·奥'Brien说过...

@Anjul,

有趣的发现-那'这不是我们网站的行为。如您在第二张屏幕截图中所见,存在init.js,但没有其他大JS双色球推荐一注。我的猜测是你'由于您在网站中使用ScriptLink控件的方式而有所不同。

关于Microsoft JS双色球推荐一注之间的依赖关系-我不'没有已建立的列表,以防您可能会有所不同,具体取决于页面上运行的JS代码。测试,测试,测试是我唯一的方法'm afraid.

谢谢,

克里斯。

萨尔·卡尔说过...

克里斯,你好
谢谢你的帖子。一世'我试图在我的主页上实现它。我已经建立了一个类,现在尝试在我的主页上引用它。我需要注册标签前缀吗?

谢谢
萨尔

克里斯·奥'Brien说过...

@Sal,

是的,您将需要TagPrefix,就像将任何控件添加到.aspx页时一样。

干杯,

克里斯。

克里斯多夫说过...

克里斯,你好

I'd希望遵循您的建议,但是-如预期的那样-删除core.js时收到错误消息。关于从标准母版页(mas​​terV4)开始删除js双色球推荐一注的干净过程的任何建议?
作为记录,当前论坛主题:
http://sharepoint.stackexchange.com/questions/15669/errors-after-removing-core-js

谢谢!

克里斯·奥'Brien说过...

@克里斯托夫,

I'我不确定这种技术最适合与标准母版页一起使用-这些东西有太多控件,而这些控件将取决于core.js中的功能。

这种方法的主要目的(在我的脑海中)是为了使母版页最少,极有可能用于匿名站点。否则,我认为您可能会追逐并删除单个控件一段时间。

那有意义吗?

C。

匿名 said...

克里斯,你好

I've遵循了您的示例,它似乎正在工作。但是,如何删除页面上的其他一些.js双色球推荐一注?例如,sp.runtime.js,sp.js和cui.js。这些双色球推荐一注不在我们的HttpContext.Current.Items集合中。

谢谢

克里斯·奥'Brien说过...

@匿名,

我不't think you'将能够删除您提到的双色球推荐一注-SharePoint以不同的方式加载它们,并且您'即使在演示模式下,也很可能会出错。

It'真可惜,但我认为's the way it 是.

HTH,

克里斯。

弗朗索瓦说过...

很棒的文章!

您提到删除无用的CSS可能会有所改善。

我尝试了一些反思,但没有't加载css时找到。

您是否有删除以下CSS的线索?
controls.css
page-layouts-21.css
rca.css
corev4.css

谢谢,

弗朗索瓦

匿名 said...

我已经使用了您的代码,将编译后的dll放在了我的Web应用程序的bin双色球推荐一注夹中(默认和扩展),并相应地更新了web.config。

当我尝试匿名访问该网站时,出现错误,我尝试检查日志,但找不到任何特定原因。

我想念什么吗?

克里斯·奥'Brien说过...

@匿名,

怕我'我不确定为什么会这样。我们在匿名的面向公众的网站上使用了本文中的代码,因此我'我不确定自己会做些什么。

克里斯。

埃德森·卡蒂(Edson Catugy)说过...

优秀的帖子!