admin 管理员组

文章数量: 887031


2024年2月20日发(作者:web服务定义)

高性能JavaScript

1、名目第一章LoadingandExecution加载和运行2第二章DataAccess数据访问.26第三章DOMScriptingDOM编程56第四章AlgorithmsandFlowControl算法和流程掌握104第五章StringsandRegularExpressions字符串和正则表达式139第六章ResponsiveInterfaces响应接口184第七章Ajax异步JavaScript和XML.216第八章ProgrammingPractices编程实践.261第九章BuildingandDeployingHigh-PerformanceJavaScriptApplications构建和部署高性能JavaScript应用.279第十章

2、Tools工具第一章第一章LoadingandExecution加载和运行加载和运行JavaScriptperformanceintheblemiscomplexbecauseoftheblockingnatureofJavaScript,whichis,mostbrowsersuseasingleprocessforbo

3、thuserinterface(UI)updatesandJavaScriptexecution,gerJavaScripttakestoexecute,ript在浏览器中的性能,可认为是开发者所要面对的最重要的可用性问题。此问题因JavaScript的阻塞特征而冗杂,也

第 15 页

就是说,当JavaScript运行时其他的事情不能被浏览器处理。事实上,大多数浏览器使用单进程处理UI更新和JavaScript运行等多个任务,而同一时间只能有

4、一个任务被执行。JavaScript运行了多长时间,那么在浏览器空闲下来响应用户输入之前的等待时间就有多长。Onabasiclevel,thismeansthattheverypresenceortheactualJavaScriptcodeisinlinewiththetagorincludedinanexternalfileisirrelevant;thepagedownloadandrenderingmuststopandwaitforthescripttocompletebeforeproceeding

5、.Thisisanecessarypartofthepage’s()inthemiddleofapage(asoftenusedbyadvertisements).Forexample:从基本层面说,这意味着标签的出现使整个页面因脚本解析、运行而出现等待。不管实际的JavaScript代码是内联的还是包含在一个不相干的外部文件中,页面下载和解析过程必需停下,等待脚本完成这些处理,然后才能继续。这是页面生命周期必不行少的部分,因为脚本可能在运行过程中

6、修改页面内容。典型的例子是()函数,例如:(“Thedateis“+(newDate()).toDateString());Whenthebrowserencountersatag

第 16 页

,asinthisHTMLpage,thereisnowayofknowingwhethertheJavaScriptwillinsertcontentintothe,introduceadditionalelements,ore,thebrowserstopsprocessingth

7、epageasitcomesin,executestheJavaScriptcode,etakesplaceforJavaScriptloadedusingthesrcattribute;thebrowsermustfirstdownloadthecodefromtheexternalfile,whichtakestime,nderinganduserinteractionarecompletelyblockedduringthistime.当浏览器遇到一个标签时,正如上面HTML页面中

8、那样,无法预知JavaScript是否在标签中添加内容。因此,浏览器停下来,运行此JavaScript代码,然后再继续解析、翻译页面。同样的事情发生在使用src属性加载JavaScript的过程中。浏览器必需首先下载外部文件的代码,这要占用一些时间,然后解析并运行此代码。此过程中,页面解析和用户交互是被完全阻塞的。ScriptPositioning脚本位置脚本位置TheHTML4specificationindicatesthatatagmaybeplacedinsidionally,scripttagstha

9、tareusedtoloadexternalJavaScriptfileshaveappearedinthe,alongwithtagstoloadexternalCSSfilesandothermetainformationabout

第 17 页

orywasthatitsbesttokeepasmanystyleandbehaviordependenciestogether,loample:HTML4文档指出,一个标签可以放在HTML文档的或标签中,可以在其中多次出现。传统上,标签用于加载外部

10、JavaScript文件。部分除此类代码外,还包含标签用于加载外部CSS文件和其他页面中间件。也就是说,最好把风格和行为所依靠的部分放在一起,首先加载他们,使得页面可以得到正确的外观和行为。例如:iptExampleHelloworld!Thoughthiscodeseemsinnocuous,itactuallyhasasevereperformanceissue:achtagblocksthepagefromcontinuingtorenderuntilithasfullydownloaded

11、andexecutedtheJavaScriptcode,mindthatbrowsersdongscriptsatthetopofthepageinthiswaytypicallyleadstoanoticeabledelay,oftenintheformofablankwhitepage,beforetheusercanevenbeginreadingorotherwiseinteractingwiththe

12、goodunderstandingofhowthisoccurs,itsusefultolook

第 18 页

1-1showswheneachscriptandthestylesheetfilegetdownloadedasthepageisloading.虽然这些代码看起来是无害的,但它们的确存在性能问题:在部分加载了三个JavaScript文件。因为每个标签阻塞了页面的解析过程,直到它完好地下载并运行了外部JavaScript代码之后,页面处理才能继续进行。用户必需忍受这种可以发觉的延迟。请记住,浏览器在遇到标签之前

13、,不会渲染页面的任何部分。用这种方法把脚本放在页面的顶端,将导致一个可以发觉的延迟,通常表现为:页面打开时,首先显示为一幅空白的页面,而此时用户即不能阅读,也不能与页面进行交互操作。为了更好地理解此过程,我们使用瀑布图来描绘每个资源的下载过程。图1-1显示出页面加载过程中,每个脚本文件和样式表文件下载的过程。riptcodeexecutionblocksotherfiledownloads图1-1,JavaScript代码运行过程阻塞其他文件下载stJavaScriptfilebeginst

14、or,nstodownloa

第 19 页

lemustwaituntilthepreviousonehasbeendownloadedandexecutedbeforethenextdown

15、eantime,thethebehaviorofmostmajorbrowserstoday.图1-1是一个令人感兴趣的模板。第一个JavaScript文件开始下载,并阻塞了其他文件的下载过程。进一步,在下载完之后和开始下载之前有一个延时,这是完全运行所需的时间。每个文件必需等待前一个文件下载完成并运行完之后,才能开始自己的下载过程。当这些文件下载时,用户面对一个空白的屏幕。这就是今日大多数浏览器的行为模式。InternetE

16、xplorer8,Firefox3.5,Safari4,goodnewsbecausethetagsdon’unately,JavaScriptdownloadsstillblockdownloadingofotherresources,nthoughdownloadingascriptdoesn’tblockotherscriptsfromdownloading,t

17、hepagemuststillwaitfortheJavaScriptcodetobedownloadedandexe

第 20 页

ethelatestbrowsershaveimprovedperformancebyallowingparalleldownloads,theproblemhasn’etExplorer8,Firefox3.5,Safari4,和Chrome2允许并行下载JavaScript文件。这个好消息说明,当一个标签正在下载外部资源时,不必阻塞其他标签。不幸的是

18、,JavaScript的下载仍旧要阻塞其他资源的下载过程,例如图片。即使脚本之间的下载过程互不阻塞,页面照旧要等待全部JavaScript代码下载并执行完成之后才能继续。所以,当浏览器通过允许并行下载提高性能之后,该问题并没有完全解决。脚本阻塞照旧是一个问题。Becausescriptsblockdownloadingofallresourcetypesonthepage,itsrecommendedtoplacealltagsasclosetothebomple:

19、因为脚本阻塞其他页面资源的下载过程,所以推举的方法是:将全部标签放在尽可能接近标签底部的位置,尽量削减对整个页面下载的影响。例如:ScriptExampleHelloworld!oughthescriptdownloadswillblockoneanother,therestofthepagehasalreadybeendownloadedanddisplayedtotheusersothattheentirepageisn’theYahoo!ExceptionalPerf

第 21 页

20、ormanceteam’sfirstruleaboutJavaScript:putscriptsatthebottom.此代码展示了所推举的标签在HTML文件中的位置。尽管脚本下载之间相互阻塞,但页面已经下载完成并且显示在用户面前了,进入页面的速度不会显得太慢。这正是“Yahoo!优越性能小组”关于JavaScript的第一条定律:将脚本放在底部。upingScripts成组脚本成组脚本Sinceeachtagblocksthepagefromrenderingduringinitialdownload,itshelpfultolimitthetotalnumberoftagscontainedi

21、imeatagisencounteredduringtheparsingofanHTMLpage,thereisgoingtobeadelaywhilethecodeisexecuted;minimizingthesedelaysimprovestheoverallperformanceofthepage.由于每个标签下载时阻塞页面解析过程,所以限制页面的总数也可以改善性能。这个规则对内联脚本和外部脚本同样适用。每当页面解析碰到一个标签时,紧接着有一段时间用于代码执行。最小化这些延迟时间可以改善页面的整

22、体性能。ThepTPrequestbringswithitadditionalperformanceoverhead,sodownloadingonesingle100KBfilewillbefasterthandownl

第 22 页

end,itshellly,alargewebsiteorwebapplicationwillhave

23、minimizetheperformanceimpactbyconcatenatingthesefilestocatenationcanhappenofflineusingabuildtool(discussedinChapter9)orinreal-timeusingatoolsuchastheYahoo!combohandler.这个问题与外部JavaScript文件处理过程略有不同。每个HTTP请求都会产生额外的性能负担,下载一个1

24、00KB的文件比下载四个25KB的文件要快。总之,削减引用外部脚本文件的数量。典型的,一个大型网站或网页应用需要多次请求JavaScript文件。你可以将这些文件整合成一个文件,只需要一个标签引用,就可以削减性能损失。这一系列的工作可通过一个打包工具实现〔我们在第9章商量〕,或者一个实时工具,诸如“Yahoo!combohandler”。Yahoo!createdthecombohandlerforuseindistributingtheYahoo!UserInterface(YUI)libraryfilesthroughtheirContentDeliveryNetwork(CDN).AnywebsitecanpullinanynumberofY

25、UIfilesbyusingacombo-handledURLandspecifyingthefilestoinclu

第 23 页

mple,thisURLincludestwofiles:/combo?2.7.0/build/yahoo/lowingsimplepagedemonstrateshowthedeferattributealtersthebehaviorofscripts:任何带有defer属性的元素在DOM加载完成之前不会被执行

26、,不管是内联脚本还是外部脚本文件,都是这样。下面的例子展示了defer属性如何影响脚本行为:ScriptDeferExamplealert(“defer“);rt(“script“);=function(){alert(“load“);};sersthatdontsupportdefer,theorderofthealertsis“defer”,“script”,and“load”.Inbrowsersthatsupportdefer,theorderof

27、thealertsis“script”,“defer”,and“load”.Notethatthedeferredelementisntexecuteduntilafterthesecondbutisexecutedbeforetheonloadeventhandleriscalled.这些代码在页面处理过程中弹出三个对话框。假如浏览器不支持defer属性,那么弹出对话框的顺序是“defer”,“script”和“load”。假如浏览器支持defer属性,那么弹出对话框的顺序是“script”,“defer”和“load”。留意,标记为defer的元素不是跟在第二个后面运行,而是在onload事件句柄处理之前被调用。Ifyourtargetbrow

28

第 24 页

sersincludeonlyInternetExplorerandFirefox3.5,avealargercross-sectionofbrowserstosupport,thereareothersolutionsthatworkinamoreconsistentmanner.假如你的目标浏览器只包括InternetExplorer和Firefox3.5,那么defer脚本的确有用。假如你需要支持跨领域的多种浏览器,那么还有更一致的实现方式。DynamicScriptElements动态脚本元素动态脚本元素TheDocumentObjectM

29、odel(DOM)allowsyouoot,theelementisntanydifferentthananyotherelementonapage:referencescanberetrievedthroughtheDOM,andtheycanbemoved,removedfromthedocument,ementcanbecreatedveryeasilyusingstandardDOMmethods:文档对象模型〔DO

30、M〕允许你使用JavaScript动态创建HTML的几乎全部文档内容。其根本在于,元素与页面其他元素没有什么不同:引用变量可以通过DOM进行检索,可以从文档中移动、删除,也可以被创建。一个新的元素可以特别简单地通过标准DOM函数创建:varscript=Element(“script“);=“text/javascript“;=““;mentsByTagName_r(“head“)[0].appendChild(script);ebegin

第 25 页

31、ortantthingaboutthistechniqueisthatthefileisdownloadedandexecutedwithoutblockingotherpageprocesses,evenplacethiscodeintheofadocumentwithoutaffectingtherestofthepage(asidefromtheoneHTTPconnectionthatisusedtodownloadthefile).新的元素加载

32、源文件。此文件当元素添加到页面之后立即开始下载。此技术的重点在于:无论在何处启动下载,文件的下载和运行都不会阻塞其他页面处理过程。你甚至可以将这些代码放在部分而不会对其余部分的页面代码造成影响〔除了用于下载文件的HTTP连接〕。Whenafileisdownloadedusingadynamicscriptnode,theretrievedcodeistypicallyexecutedimmediately(exceptinFirefoxandOpera,whichwillwaituntilanypreviousdynamicscriptnodeshaveexecuted).Thisworkswellwhenthescriptiss

33、elf-executingbutcanbeproblematicase,accomplishedusingeventsthatarefiredbythedynamicnode.当文件使用动态脚本节点下载时,返回的代码通常马上执行〔除了Firefox和Opera,他们将等待此前的全部动态脚本节点执行完毕〕。当脚本是

第 26 页

“自运行”类型时这一机制运行正常,但是假如脚本只包含供页面其他

34、脚本调用调用的接口,则会带来问题。这种状况下,你需要跟踪脚本下载完成并预备妥当的状况。可以使用动态节点发出事件得到相关信息。Firefox,Opera,Chrome,andSafari3+thereforebenotifiedwhenthescriptisreadybylisteningforthisevent:efox,Opera,Chorme和Safari3+会在节点接收完成之后发出一个load事件。你可以监听这一事件,以得到脚本预备好的通知:varscript=docume

35、Element(“script“)=“text/javascript“;//Firefox,Opera,Chrome,Safari3+=function(){alert(“Scriptloaded!“);};=““;mentsByTagName_r(“head“)[0].appendChild(script);InternetExplorerssareadyStatepropert

36、yontheelemrefivepossiblevaluesforreadyState:InternetExplorer支持另一种实现方式,它发出一个readystatechange

第 27 页

事件。元素有一个readyState属性,它的值随着下载外部文件的过程而转变。readyState有五种取值:“uninitialized“Thedefaultstate“uninitialized”默认状态“loading“Downloadhasbegun“loading”“loaded“Downloadhascomple

37、ted“loaded”下载完成下载开始“interactive“Dataiscompletelydownloadedbutisntfullyavailable“interactive”下载完成但尚不行用“complete““complete”全部数据已经预备好MicrosoftsdocumentationforreadyStateandeachofthepossiblevaluesseemstoindicatethatnotallstateswillbeusedduringthelifetimeoftheelement,butthereisnoindicationas

38、tice,thetwostatesofmostinterestare“loaded“and“complete“.InternetExplorerisinconsistentwithwhichofthesetworeadyStatevaluesindicatesthefinalstate,assometimestheelementwillreachthe“loaded“statebutneverreach“complete“whereasothertimes“complete“willbereachedwithout“loaded“estwa

39、ytousethereadystatechangeeventistocheckforbothofthesestates

第 28 页

andremovetheeventhandlerwheneitheroneoccurs(toensuretheeventisnthandledtwice):微软文档上说,在元素的生命周期中,readyState的这些取值不肯定全部出现,但并没有指出哪些取值总会被用到。实践中,我们最感兴趣的是“loaded”和“complete”状态。InternetExplorer对这两个readyState值所表示的最终状态并不一致,有时元素会得到“loader”却从不出现“complete”,但另外一些状况下出现“complete”而用不到“l

40、oaded”。最安全的方法就是在readystatechange事件中检查这两种状态,并且当其中一种状态出现时,删除readystatechange事件句柄〔保证事件不会被处理两次〕:varscript=

第 29 页


本文标签: 下载 页面 脚本 文件 过程