日本搞逼视频_黄色一级片免费在线观看_色99久久_性明星video另类hd_欧美77_综合在线视频

國內(nèi)最全IT社區(qū)平臺 聯(lián)系我們 | 收藏本站
阿里云優(yōu)惠2
您當前位置:首頁 > web前端 > htmlcss > JavaScript學(xué)習--Item26 異步的腳本加載

JavaScript學(xué)習--Item26 異步的腳本加載

來源:程序員人生   發(fā)布時間:2016-06-13 11:46:46 閱讀次數(shù):3299次

先來看這行代碼:

<script src = "allMyClientSideCode.js"></script>

這有點兒……不怎樣樣。“這該放在哪兒?”開發(fā)人員會奇怪,“靠上點,放到<head>標簽里?還是靠下點,放到<body>標簽里?”這兩種做法都會讓富腳本站點的下場很凄慘。<head>標簽里的大腳本會滯壓所有頁面渲染工作,使得用戶在腳本加載終了之前1直處于“白屏死機”狀態(tài)。而<body>標簽?zāi)┪驳拇竽_本只會讓用戶看到毫無生命力的靜態(tài)頁面,本來應(yīng)當進行客戶端渲染的地方卻散布著不起作用
的控件和空空如也的方框。

完善解決這個問題需要對腳本分而治之:那些負責讓頁面更好看、更好用的腳本應(yīng)當立即加載,而那些可以待會兒再加載的腳本稍后再加載。但是怎樣才能既滯壓這些腳本,又能保證它們在被調(diào)用時的可用性呢?

1、<script>標簽的再認識

現(xiàn)代閱讀器中的<script>標簽分成了兩種新類型:經(jīng)典型和非阻塞型。接下來討論如何應(yīng)用這兩種標簽來盡快加載頁面。

1、阻塞型腳本何去何從?

標準版本的<script>標簽常常被稱作阻塞型標簽。這個詞必須放在上下文中進行理解:現(xiàn)代閱讀器看到阻塞型<script>標簽時,會跳過阻塞點繼續(xù)讀取文檔及下載其他資源(腳本和樣式表)。但直到腳本下載終了并運行以后,閱讀器才會評估阻塞點以后的那些資源。因此,如果網(wǎng)頁文檔的<head>標簽里有5 個阻塞型<script>標簽,則在所有這5 個腳本均下載終了并運行之前,用戶除頁面標題以外看不到任何東西。不但如此,即使這些腳本運行了,它們也只能看到阻塞點之前的那部份文檔。如果想看到<body>標簽中正等待加載的那些好東西,就必須給像document.onreadystatechange 這樣的事件綁定1個事件處理器。

基于上述緣由,現(xiàn)在愈來愈流行把腳本放在頁面<body>標簽的尾部。這樣,1方面用戶可以更快地看到頁面,另外一方面腳本也能夠主動密切接觸DOM 而無需等待事件來觸發(fā)自己。對大多數(shù)腳本而言,這次“搬家”是個巨大的進步。

但并不是所有腳本都1樣。在向下搬動腳本之前,請先問自己2 個問題。

  • 該腳本是不是有可能被<body>標簽里的內(nèi)聯(lián)JavaScript 直接調(diào)用?答案可能1目了然,但仍值得核對1遍。

  • 該腳本是不是會影響已渲染頁面的外觀?Typekit 宿主字體就是1個例子。如果把Typekit 腳本放在文檔末尾,那末頁面文本就會渲染兩次,即讀取文檔時即刻渲染,腳本運行時再次渲染。

上述問題只要有1個答案是肯定的,那末該腳本就應(yīng)當放在<head>標簽中,否則就能夠放在<body>標簽中,文檔形如:

<html> <head> <!--metadata and stylesheets go here --> <script src="headScripts.js"></scripts> </head> <body> <!-- content goes here --> <script src="bodyScripts.js"></script> </body> </html>

這確切大大縮短了加載時間,但要注意1點,這可能讓用戶有機會在加載bodyScripts.js 之前與頁面交互。

2、 腳本的提早加載與延遲運行

上面建議將大多數(shù)腳本放在<body>中,由于這樣既能讓用戶更快地看到網(wǎng)頁,又能避免操控DOM之前綁定“就緒”事件的開消。但這類方式也有1個缺點,即閱讀器在加載完全個文檔之前沒法加載這些腳本,這對那些通過慢速連接傳送的大型文檔來講會是1大瓶頸

理想情況下,腳本的加載應(yīng)當與文檔的加載同時進行,并且不影響DOM 的渲染。這樣,1旦文檔就緒就能夠運行腳本,由于已依照<script>標簽的次序加載了相應(yīng)腳本。

如果大家已讀到這里了,那末1定會迫不及待地想寫1個自定義Ajax 腳本加載器以滿足這樣的需求!不過,大多數(shù)閱讀器都支持1個更加簡單的解決方案。

<script defer src = "deferredScript.js">

添加defer(延遲)屬性相當于對閱讀器說:“請馬上開始加載這個腳本吧,但是,請等到文檔就緒且所有此前具有defer 屬性的腳本都結(jié)束運行以后再運行它。”在文檔<head>標簽里放入延遲腳本,既能帶來腳本置于<body>標簽時的全部好處,又能讓大文檔的加載速度大幅提升!

不足的地方就是,并不是所有閱讀器都支持defer屬性。這意味著,如果想確保自己的延遲腳本能在文檔加載后運行,就必須將所有延遲腳本的代碼都封裝在諸如jQuery 之$(document).ready 之類的結(jié)構(gòu)中。

上1節(jié)的頁面例子改進以下:

<html> <head> <!-- metadata and stylesheets go here --> <script src="headScripts.js"></scripts> <script defer src="http://www.jyygyx.com/upload/caiji/20160601/deferredScripts.js"></script> </head> <body> <!-- content goes here --> </body> </html>

請記住deferredScripts 的封裝很重要,這樣即便閱讀器不支持defer,deferredScripts 也會在文檔就緒事件以后才運行。如果頁面主體內(nèi)容遠遠超過幾千字節(jié),那末付出這點代價是完全值得的。

3、 腳本的并行加載

如果你是瑣屑較量到毫秒級頁面加載時間的完善主義者,那末defer或許就像是淡而無味的薄鹽醬油。你可不想1直等到此前所有的defer 腳本都運行結(jié)束,固然也肯定不想等到文檔就緒以后才運行這些腳本,你就是想盡快加載并且盡快運行這些腳本。這也正是現(xiàn)代閱讀器提供了async(異步)屬性的緣由。

<script async src = "speedyGonzales.js"> <script async src = "roadRunner.js">

如果說defer 讓我們想到1種靜靜等待文檔加載的有序排隊場景,那末async 就會讓我們想到混亂的無政府狀態(tài)。前面給出的那兩個腳本會以任意次序運行,而且只要JavaScript 引擎可用就會立即運行,而不論文檔就緒與否。

對大多數(shù)腳本來講,async 是1塊難以下咽的雞肋。async 不像defer那樣得到廣泛的支持。同時,由于異步腳本會在任意時刻運行,它實在太容易引發(fā)海森堡蟻蟲之災(zāi)了(腳本恰好結(jié)束加載時就會蟻蟲4起)。

當我們加載1些第3方腳本,而且也不在意它們誰先運行誰后運行。因此,對這些第3方腳本使用async 屬性,相當于1分錢沒花就提升了它們的運行速度。

上1個頁面示例再添加兩個獨立的第3方小部件,得到的結(jié)果以下:

<html> <head> <!-- metadata and stylesheets go here --> <script src="headScripts.js"></scripts> <script src="http://www.jyygyx.com/upload/caiji/20160601/deferredScripts.js" defer></script> </head> <body> <!-- content goes here --> <script async defer src="feedbackWidget.js"></script> <script async defer src="chatWidget.js"></script> </body> </html>

這個頁面結(jié)構(gòu)清晰展現(xiàn)了腳本的優(yōu)先次序。對絕大多數(shù)閱讀器,DOM的渲染只會延遲至headScripts.js 結(jié)束運行時。進行DOM渲染的同時會在后臺加載deferredScripts.js。接著,在DOM 渲染結(jié)束時將運行deferredScripts.js 和那兩個小部件腳本。這兩個小部件腳本在那些支持async 的閱讀器中會做無序運行。如果不肯定這是不是妥當,請勿使用async!

2、可編程的腳本加載

雖然<script>標簽簡單得使人心動,但有些情況確切需要更精致的腳本加載方式。我們可能只想給那些滿足1定條件的用戶加載某個腳本,比方白金會員或到達1定級別的玩家,也可能只想當用戶單擊激活時才加載某個特性,比方聊天小部件。

1、直接加載腳本

我們可以用類似下面這樣的代碼來插入<script>標簽。

var head = document.getElementsByTagName('head')[0]; var script = document.createElement('script'); script.src = '/js/feature.js'; head.appendChild(script);

稍等,我們?nèi)绾尾拍苤滥_本什么時候加載結(jié)束呢?我們可以給腳本本身添加1些代碼以觸發(fā)事件,但如果要為每一個待加載腳本都添加這樣的代碼,那也太鬧心了。或是另外1種情況,即我們不可能給第3方服務(wù)器上的腳本添加這樣的代碼。HTML5 規(guī)范定義了1個可以綁定回調(diào)的onload 屬性。

script.onload = function() { // 現(xiàn)在可以調(diào)用腳本里定義的函數(shù)了 };

不過, IE8 及更老的版本其實不支持onload , 它們支持的是onreadystatechange。某些閱讀器在插入<script>標簽時還會出現(xiàn)1些“靈異事件”。而且,這里乃至還沒談到毛病處理呢!為了不
所有這些使人頭疼的問題,在此強烈建議使用腳本加載庫。

3、yepnope的條件加載

yepnope是1個簡單的、輕量級的腳本加載庫(緊縮后的精簡版只有1.7KB),其設(shè)計目標就是真誠服務(wù)于最多見的動態(tài)腳本加載需求。

yepnope 最簡單的用法是,加載腳本并對腳本完成運行這1事件返回1個回調(diào)。

yepnope({ load: 'oompaLoompas.js', callback: function() { console.log('oompa-Loompas ready!'); } });

還是無動于中?下面我們要用yepnope 來并行加載多個腳本并按給定次序運行它們。舉個例子,假定我們想加載Backbone.js,而這個腳本又依賴于Underscore.js。為此,我們只需用數(shù)組情勢提供這兩個腳本的位置作為加載參數(shù)。

yepnope({ load: ['underscore.js', 'backbone.js'], complete: function() { // 這里是Backbone 的業(yè)務(wù)邏輯 } });

請注意,這里使用了complete(完成)而不是callback(回調(diào))。

其差別在于,腳本加載列表中的每一個資源均會運行callback,而只有當所有腳本都加載完成后才會運行complete。yepnope 的標志性特點是條件加載。給定test 參數(shù),yepnope 會根據(jù)該參數(shù)值是不是為真而加載不同的資源。舉個例子,可以以1定的準確度判斷用戶是不是在用觸摸屏裝備,從而據(jù)此相應(yīng)地加載不同的樣式表及腳本。

yepnope({ test: Modernizr.touch, yep: ['touchStyles.css', 'touchApplication.js'], nope: ['mouseStyles.css', 'mouseApplication.js'], complete: function() { // 不論是哪種情況,利用程序均已就緒! } });

我們只用寥寥幾行代碼就搭好了舞臺,可以基于用戶的接入裝備而給他們完全不同的使用體驗。固然,不是所有的條件加載都需要備齊yep(是)和nope(否)這兩種測試結(jié)果。yepnope 最多見的用法之1就是加載墊片腳本以彌補老式閱讀器缺失的功能。

yepnope({ test: window.json,nope: ['json2.js'], complete: function() { // 現(xiàn)在可以放心腸用JSON 了 } });

頁面使用了yepnope 以后應(yīng)當變成下面這類漂亮的標記結(jié)構(gòu):

<html> <head> <!-- metadata and stylesheets go here --> <script src="headScripts.js"></scripts> <script src="http://www.jyygyx.com/upload/caiji/20160601/deferredScripts.js" defer></script> </head> <body> <!-- content goes here --> </body> </html>

很眼熟?這個結(jié)構(gòu)和討論defer 屬性那1節(jié)給出的結(jié)構(gòu)1樣,唯1的區(qū)分是這里的某個腳本文件已拼接了yepnope.js(極可能就在deferredScripts.js 的頂部),這樣就能夠獨立地加載那些根據(jù)條件再加載的腳本(由于閱讀器需要墊片腳本)和那些想要動態(tài)加載的腳本(以便回利用戶的動作)。結(jié)果將是1個更小巧的deferredScripts.js。

4、Require.js/AMD 模塊化加載

開發(fā)人員想通過腳本加載器讓混亂不堪的富腳本利用變得更規(guī)整有序1些,而Require.js 就是這樣1種選擇。Require.js 這個強大的工具包能夠自動和AMD技術(shù)1起捋順哪怕最復(fù)雜的腳本依賴圖。

現(xiàn)在先來看1個用到Require.js 同名函數(shù)的簡單腳本加載示例。

require(['moment'], function(moment) { console.log(moment().format('dddd')); // 星期幾 });

require 函數(shù)接受1個由模塊名稱構(gòu)成的數(shù)組,然后并行地加載所有這些腳本模塊。與yepnope 不同,Require.js 不會保證按順序運行目標腳本,只是保證它們的運行次序能滿足各自的依賴性要求,但條件是
這些腳本的定義遵照了AMD(Asynchronous Module Definition,異步模塊定義)規(guī)范。
案例1: 加載 JavaScript 文件

<script src="./js/require.js"></script> <script> require(["./js/a.js", "./js/b.js"], function() { myFunctionA(); myFunctionB(); }); </script>

如案例1 所示,有兩個 JavaScript 文件 a.js 和 b.js,里面各自定義了 myFunctionA 和 myFunctionB 兩個方法,通過下面這個方式可以用 RequireJS 來加載這兩個文件,在 function 部份的代碼可以援用這兩個文件里的方法。

require 方法里的這個字符串數(shù)組參數(shù)可以允許不同的值,當字符串是以”.js”結(jié)尾,或以”/”開頭,或就是1個 URL 時,RequireJS 會認為用戶是在直接加載1個 JavaScript 文件,否則,當字符串是類似”my/module”的時候,它會認為這是1個模塊,并且會以用戶配置的 baseUrl 和 paths 來加載相應(yīng)的模塊所在的 JavaScript 文件。配置的部份會在稍后詳細介紹。

這里要指出的是,RequireJS 默許情況下并沒有保證 myFunctionA 和 myFunctionB 1定是在頁面加載完成以后履行的,在有需要保證頁面加載以后履行腳本時,RequireJS 提供了1個獨立的 domReady 模塊,需要去 RequireJS 官方網(wǎng)站下載這個模塊,它并沒有包括在 RequireJS 中。有了 domReady 模塊,案例1 的代碼稍做修改加上對 domReady 的依賴就能夠了。

案例2: 頁面加載后履行 JavaScript

<script src="./js/require.js"></script> <script> require(["domReady!", "./js/a.js", "./js/b.js"], function() { myFunctionA(); myFunctionB(); }); </script>

履行案例2的代碼后,通過 Firebug 可以看到 RequireJS 會在當前的頁面上插入為 a.js 和 b.js 分別聲明了1個 < script> 標簽,用于異步方式下載 JavaScript 文件。async 屬性目前絕大部份閱讀器已支持,它表明了這個 < script> 標簽中的 js 文件不會阻塞其他頁面內(nèi)容的下載。

案例3:RequireJS 插入的 < script>

<script type="text/javascript" charset="utf⑻" async="" data-requirecontext="_" data-requiremodule="js/a.js" src="js/a.js"></script>

AMD推行1個由Require.js 負責提供的名叫define 的全局函數(shù),該函數(shù)有3 個參數(shù):

  • 模塊名稱,
  • 模塊依賴性列表,
  • 在那些依賴性模塊加載結(jié)束時觸發(fā)的回調(diào)。

使用 RequireJS 來定義 JavaScript 模塊

這里的 JavaScript 模塊與傳統(tǒng)的 JavaScript 代碼不1樣的地方在于它不必訪問全局的變量。模塊化的設(shè)計使得 JavaScript 代碼在需要訪問”全局變量”的時候,都可以通過依賴關(guān)系,把這些”全局變量”作為參數(shù)傳遞到模塊的實現(xiàn)體里,在實現(xiàn)中就避免了訪問或聲明全局的變量或函數(shù),有效的避免大量而且復(fù)雜的命名空間管理。

猶如 CommonJS 的 AMD 規(guī)范所述,定義 JavaScript 模塊是通過 define 方法來實現(xiàn)的。

下面我們先來看1個簡單的例子,這個例子通過定義1個 student 模塊和1個 class 模塊,在主程序中實現(xiàn)創(chuàng)建 student 對象并將 student 對象放到 class 中去。

案例4: student 模塊,student.js

define(function(){ return { createStudent: function(name, gender){ return { name: name, gender: gender }; } }; });

案例5:class 模塊,class.js

define(function() { var allStudents = []; return { classID: "001", department: "computer", addToClass: function(student) { allStudents.push(student); }, getClassSize: function() { return allStudents.length; } }; } );

案例6: 主程序

require(["js/student", "js/class"], function(student, clz) { clz.addToClass(student.createStudent("Jack", "male")); clz.addToClass(student.createStudent("Rose", "female")); console.log(clz.getClassSize()); // 輸出 2 });

student 模塊和 class 模塊都是獨立的模塊,下面我們再定義1個新的模塊,這個模塊依賴 student 和 class 模塊,這樣主程序部份的邏輯也能夠包裝進去了。

案例7: 依賴 student 和 class 模塊的 manager 模塊,manager.js

define(["js/student", "js/class"], function(student, clz){ return { addNewStudent: function(name, gender){ clz.addToClass(student.createStudent(name, gender)); }, getMyClassSize: function(){ return clz.getClassSize(); } }; });

案例8:新的主程序

require(["js/manager"], function(manager) { manager.addNewStudent("Jack", "male"); manager.addNewStudent("Rose", "female"); console.log(manager.getMyClassSize());// 輸出 2 });

通過上面的代碼示例,我們已清楚的了解了如何寫1個模塊,這個模塊如何被使用,模塊間的依賴關(guān)系如何定義。

5、小結(jié)

要想讓自己的站點更快捷,可以異步加載那些暫時用不到的腳本。為此最簡單的做法是審慎地使用defer 屬性和async 屬性。如果要求根據(jù)條件來加載腳本,請斟酌像yepnope 這樣的腳本加載器。如果站點存在大量相互依賴的腳本,請斟酌Require.js。選擇最合適任務(wù)的工具,然后使用它,享受它帶來的便捷。

參考:

  • JavaScript異步編程
  • RequireJS模塊化加載
生活不易,碼農(nóng)辛苦
如果您覺得本網(wǎng)站對您的學(xué)習有所幫助,可以手機掃描二維碼進行捐贈
程序員人生
------分隔線----------------------------
分享到:
------分隔線----------------------------
關(guān)閉
程序員人生
主站蜘蛛池模板: 一区二区欧美精品 | 欧美日韩视频一区二区三区 | 成人在线高清 | 91精品啪在线观看国产81旧版 | 亚洲一区二区免费电影 | 99精品网站 | 国产在线播放av | av免费网站在线观看 | a国产精品 | 亚洲国产成人精品女人久 | 黄色在线 | 亚洲精品久久 | 国产一区精品在线 | av中文字幕第一页 | 色综合天天综合网国产成人网 | 中文字幕国产日韩 | av片免费在线播放 | 国产成人精品一区二区三区视频 | 天天色综合天天色 | 免费在线观看黄网站 | 久久久久久久成人 | 亚洲综合一区在线 | 久久久蜜臀国产一区二区 | 欧美视频一区二区在线观看 | 国产一区欧美 | 岛国视频在线观看 | www国产亚洲精品 | www.91.com在线观看 | 欧美精品一区二区三区在线 | 中文天堂视频在线 | 三级日韩 | 国产精品视频一区二区三区不卡 | 韩日av在线| 日韩久| 亚洲精品美女久久久久99 | 欧美视频日韩 | 亚洲欧洲视频在线观看 | 欧美成人一区二区三区片免费 | 天天干天天射综合网 | 黄色一级片在线 | 91精品国产综合久久福利 |