前端知識(shí)體系總結(jié)

數(shù)據(jù)結(jié)構(gòu)與算法


棧和隊(duì)列的區(qū)別

網(wǎng)絡(luò)基礎(chǔ)


HTTP 無狀態(tài)怎么理解

可以從REST的角度來理解這個(gè)問題。我們知道REST風(fēng)格是無狀態(tài)的。而REST是基于HTTP協(xié)議的,所以REST的無狀態(tài)基本就可以解釋HTTP的無狀態(tài)。

TCP三次握手與四次揮手

三次握手
為了準(zhǔn)確無誤地將數(shù)據(jù)送到目標(biāo)處,TCP采用三次握手策略,過程中使用了TCP的標(biāo)志:SYN和ACK.
三次握手
Client --> 置SYN標(biāo)志 序列號(hào) = J,確認(rèn)號(hào) = 0 ----> Server
Client <-- 置SYN標(biāo)志 置ACK標(biāo)志 序列號(hào) = K, 確認(rèn)號(hào) = J + 1 <-- Server
Clinet --> 置ACK標(biāo)志 序列號(hào) = J + 1,確認(rèn)號(hào) = K + 1 --> Server
四次揮手
Client -> 發(fā)送FIN 序列號(hào) = J,確認(rèn)號(hào) = 0 --> Server
Server -> 發(fā)送ACK 確認(rèn)號(hào) = J + 1
Server -> 發(fā)送FIN 序列號(hào) = K, 確認(rèn)號(hào) = 0 -> Client
Client -> 發(fā)送ACK 確認(rèn)號(hào) = K+1

HTTPS

HTTPS是在HTTP與TCP之間添加一個(gè)安全協(xié)議層(SSL或TSL).
網(wǎng)絡(luò)請(qǐng)求中往往中間需要很多服務(wù)器或者路由器的轉(zhuǎn)發(fā),中間的節(jié)點(diǎn)都可能篡改信息,而如果使用HTTPS,密鑰在請(qǐng)求客戶端和終點(diǎn)站才有,所以相對(duì)于HTTP會(huì)更安全,就是因?yàn)镠TTPs利用SSL/TSL協(xié)議傳輸,它包含證書等安全信息,保證了傳輸過程的安全性。

前端其他問題


前端工程價(jià)值

  • 解放前后端互相在開發(fā)進(jìn)度上的依賴問題,前后端可以同時(shí)進(jìn)行
  • 為簡化用戶使用,提高交互體驗(yàn)/用戶體驗(yàn)
  • 解決瀏覽器兼容問題
  • 提高瀏覽速度(性能)
  • 跨平臺(tái)應(yīng)用的支持
  • 展現(xiàn)數(shù)據(jù),數(shù)據(jù)處理
  • 降低后端壓力

瀏覽器緩存技術(shù)

** Etag **

當(dāng)發(fā)送一個(gè)服務(wù)器的請(qǐng)求時(shí),瀏覽器會(huì)首先進(jìn)行緩存過期的判斷,瀏覽器根據(jù)緩存過期的時(shí)間判斷緩存文件是否過期。

  • 若沒有過期,則不向服務(wù)器發(fā)送請(qǐng)求,直接使用緩存中的結(jié)果

Session Cookie LocalStorage

全局環(huán)境與局部環(huán)境

JS對(duì)象 BOM DOM

http://www.runoob.com/jsref/dom-obj-event.html

瀏覽器的基本組成與頁面渲染原理

為什么不能頻繁操作DOM

重排與重繪

前端模塊化


https://segmentfault.com/p/1210000007731421?from=singlemessage&isappinstalled=1
CommonJs規(guī)范 - NodeJs實(shí)現(xiàn) 同步
分支 異步
AMD RequireJs
CMD SeaJs
UMD 前后端整合
ES6 - I import export

前端優(yōu)化


前端兼容性


漸進(jìn)增強(qiáng)和優(yōu)雅降級(jí)

** 漸進(jìn)增強(qiáng) ** :針對(duì)低版本瀏覽器進(jìn)行構(gòu)建頁面,保證最基本的功能,然后再針對(duì)高級(jí)瀏覽器進(jìn)行效果、交互等改進(jìn)和追加功能達(dá)到更好的用戶體驗(yàn)。
** 優(yōu)雅降級(jí) ** :一開始就構(gòu)建完整的功能,然后再針對(duì)低版本瀏覽器進(jìn)行兼容。

前端安全性


常見的幾種安全攻擊

SQL 注入
XSS
CSRF

前端工具


模塊打包工具

** Webpack **

  1. 模塊打包工具
  1. 管理依賴模塊間依賴,生成優(yōu)化并且合并后的靜態(tài)資源文件
  2. 編譯輸出靜態(tài)文件,將代碼分割成不同的chunk,實(shí)現(xiàn)按需加載,降低初始化時(shí)間
  3. 所有文件都是模塊, html, js, css, 圖片等
  4. 模塊加載器, 支持串聯(lián)操作
  5. 以commonJs的形式書寫,但對(duì)AMD/CMD的支持也比較全面,方便舊項(xiàng)目進(jìn)行代碼遷移

HTML5


Webworker

Js中的多線程實(shí)現(xiàn)

Websocket

SVG

Canvas

CSS


position的值, relative和absolute分別是相對(duì)于誰進(jìn)行定位的?

盒模型

IE盒模型與其他瀏覽器的盒模型

CSS選擇器的優(yōu)先級(jí)

JavaScript


ES6

參考:http://es6.ruanyifeng.com/

Js運(yùn)行機(jī)制

http://www.ruanyifeng.com/blog/2014/10/event-loop.html

  • Javascript 是單線程
    Javascript 的單線程與它的用途有關(guān)
  • 任務(wù)隊(duì)列
    任務(wù)可分為兩種,一種是同步任務(wù),一種是異步任務(wù)。
    ** 同步任務(wù) :在主線程上排隊(duì)執(zhí)行的任務(wù),只有前一個(gè)任務(wù)執(zhí)行完畢后,才能執(zhí)行后一個(gè)任務(wù);
    ** 異步任務(wù) :不進(jìn)入主線程,而進(jìn)入任務(wù)隊(duì)列(task queue)的任務(wù),只有任務(wù)隊(duì)列通知主線程,某個(gè)異步任務(wù)要以執(zhí)行了,該任務(wù)才會(huì)進(jìn)入主線程執(zhí)行。
    ** 異步任務(wù)運(yùn)行機(jī)制如下:

    Paste_Image.png

    1)所有同步任務(wù)都在主線程上執(zhí)行,形成一個(gè)執(zhí)行棧(execution context stack)。
    2)主線程之外,還存在一個(gè)"任務(wù)隊(duì)列"(task queue)。只要異步任務(wù)有了運(yùn)行結(jié)果,就在"任務(wù)隊(duì)列"之中放置一個(gè)事件。
    3)一旦"執(zhí)行棧"中的所有同步任務(wù)執(zhí)行完畢,系統(tǒng)就會(huì)讀取"任務(wù)隊(duì)列",看看里面有哪些事件。那些對(duì)應(yīng)的異步任務(wù),于是結(jié)束等待狀態(tài),進(jìn)入執(zhí)行棧,開始執(zhí)行。
    4)主線程不斷重復(fù)上面的第三步。
    ** 只要主線程空了,就會(huì)去讀取"任務(wù)隊(duì)列",這就是JavaScript的運(yùn)行機(jī)制。這個(gè)過程會(huì)不斷重復(fù)。
  • 事件和任務(wù)隊(duì)列
    ** 任務(wù)隊(duì)列 **
  1. 是一個(gè)事件的隊(duì)列,也可以理解成是消息隊(duì)列。主線程讀取任務(wù)隊(duì)列就是讀取里面有哪些事件。
  2. 任務(wù)隊(duì)列里面不止有IO設(shè)備的事件,也有用戶操作產(chǎn)生的事件。只要指定過回調(diào)函數(shù),這些事件發(fā)生時(shí)就會(huì)進(jìn)入任務(wù)隊(duì)列中,等待主線程讀取。主線程執(zhí)行異步任務(wù),就是執(zhí)行對(duì)應(yīng)的回調(diào)函數(shù)。
  3. 主線程會(huì)首先檢查執(zhí)行時(shí)間,某些事件只有到了規(guī)定的時(shí)間,才能返回主線程。如setTimeout().
    ** Event Loop **
    主線程從事件隊(duì)列中讀取事件的過程是不斷循環(huán)的,所以整個(gè)的運(yùn)行機(jī)制就是一個(gè)Event Loop,也叫事件循環(huán)。


    Paste_Image.png
  4. 定時(shí)器
    除了放置異步任務(wù)的事件,"任務(wù)隊(duì)列"還可以放置定時(shí)事件,即指定某些代碼在多少時(shí)間之后執(zhí)行。這叫做"定時(shí)器"(timer)功能,也就是定時(shí)執(zhí)行的代碼。
    setTimeout()
    setInterval()
    HTML5標(biāo)準(zhǔn)規(guī)定了setTimeout()的第二個(gè)參數(shù)的最小值(最短間隔),不得低于4毫秒,如果低于這個(gè)值,就會(huì)自動(dòng)增加。在此之前,老版本的瀏覽器都將最短間隔設(shè)為10毫秒。另外,對(duì)于那些DOM的變動(dòng)(尤其是涉及頁面重新渲染的部分),通常不會(huì)立即執(zhí)行,而是每16毫秒執(zhí)行一次。這時(shí)使用requestAnimationFrame()的效果要好于setTimeout()。
    需要注意的是,setTimeout()只是將事件插入了"任務(wù)隊(duì)列",必須等到當(dāng)前代碼(執(zhí)行棧)執(zhí)行完,主線程才會(huì)去執(zhí)行它指定的回調(diào)函數(shù)。要是當(dāng)前代碼耗時(shí)很長,有可能要等很久,所以并沒有辦法保證,回調(diào)函數(shù)一定會(huì)在setTimeout()指定的時(shí)間執(zhí)行。

Js事件模型

參考:https://segmentfault.com/a/1190000006934031?from=singlemessage&isappinstalled=1
DOM事件探秘

  • ** 發(fā)布訂閱模式(觀察者模式)**
    Javascript的事件模型基于發(fā)布請(qǐng)閱模式,可以讓多個(gè)觀察者對(duì)象同時(shí)監(jiān)聽某一個(gè)主題對(duì)象,這個(gè)主題對(duì)象的狀態(tài)變化會(huì)通知所有的訂閱者,使得它們能夠做出反應(yīng)。
    以下是用js實(shí)現(xiàn)的一個(gè)發(fā)布訂閱模式
var events = (function () {
    var topics = {};
    return {
        publish: function (topic, info) {
            console.log("publish a topic:" + topic);
            if (topics.hasOwnProperty(topic)) {
                topics[topic].forEach(function(handler) {
                    handler(info ? info : {});
                });
            }
        },
        subscribe: function(topic, handler) {
            console.log("subscribe an topic" + topic);
            if (!topics.hasOwnProperty(topic)) {
                topics[topic] = [];
            }
            topics[topic].push(handler);
        },
        remove: function(topic, handler) {
            if (!topics.hasOwnProperty(topics)) {
                return;
            }
            var handlerIndex = -1;
            topics[topic].forEach(function (element, index) {
                if (element === handler) {
                    handlerIndex = index;
                }
            });
            if (handlerIndex >= 0) {
                topics[topic].splice(handlerIndex, 1);
            }
        }
    };
})();
var handler = function (info) {
    console.log(info);
}
events.subscribe("hello", handler);
events.publish("hello", "hello world");
  • ** 事件與事件流 **
    事件是與瀏覽器或文檔交互的瞬間,如點(diǎn)擊按鈕,填寫表格等,它是JS與HTML之間交互的橋梁。DOM是樹形結(jié)構(gòu),如果同時(shí)給父子節(jié)點(diǎn)都綁定事件時(shí),當(dāng)觸發(fā)子節(jié)點(diǎn)的時(shí)候,這兩個(gè)事件的發(fā)生順序如何決定?這就涉及到事件流的概念,它描述的是頁面中接受事件的順序。
    事件流有兩種:
    ** 事件冒泡(Event Capturing): ** 是一種從下往上的傳播方式。事件最開始由最具體的元素(文檔中嵌套層次最深的那個(gè)節(jié)點(diǎn)接受, 也就是DOM最低層的子節(jié)點(diǎn)), 然后逐漸向上傳播到最不具體的那個(gè)節(jié)點(diǎn),也就是DOM中最高層的父節(jié)點(diǎn)。
    ** 事件捕獲(Event Bubbling): **與事件冒泡相反。事件最開始由不太具體的節(jié)點(diǎn)最早接受事件, 而最具體的節(jié)點(diǎn)最后接受事件。
  • ** 事件模型 **
    ** DOM 0級(jí)模型 **
    HTML代碼中直接綁定:
<input type="button" onclick="fun()">

通過JS代碼指定屬性值:

var btn = document.getElementById('.btn');btn.onclick = fun;

移除監(jiān)聽函數(shù):

btn.onclick = null;

這種方式所有瀏覽器都兼容,但是邏輯與顯示并沒有分離。
** IE事件模型 **
IE事件模型共有兩個(gè)過程:
事件處理階段(target phase)。事件到達(dá)目標(biāo)元素, 觸發(fā)目標(biāo)元素的監(jiān)聽函數(shù)。
事件冒泡階段(bubbling phase)。事件從目標(biāo)元素冒泡到document, 依次檢查經(jīng)過的節(jié)點(diǎn)是否綁定了事件監(jiān)聽函數(shù),如果有則執(zhí)行。
事件綁定監(jiān)聽函數(shù)的方式如下:

attachEvent(eventType, handler)

事件移除監(jiān)聽函數(shù)的方式如下:

detachEvent(eventType, handler)

參數(shù)說明:
eventType指定事件類型(注意加on)
handler是事件處理函數(shù)
Example:

var btn = document.getElementById('.btn');
btn.attachEvent(‘onclick’, showMessage);
btn.detachEvent(‘onclick’, showMessage);

** DOM 2級(jí)模型 **
屬于W3C標(biāo)準(zhǔn)模型,現(xiàn)代瀏覽器(除IE6-8之外的瀏覽器)都支持該模型。在該事件模型中,一次事件共有三個(gè)過程:
事件捕獲階段(capturing phase)。事件從document一直向下傳播到目標(biāo)元素, 依次檢查經(jīng)過的節(jié)點(diǎn)是否綁定了事件監(jiān)聽函數(shù),如果有則執(zhí)行。
事件處理階段(target phase)。事件到達(dá)目標(biāo)元素, 觸發(fā)目標(biāo)元素的監(jiān)聽函數(shù)。
事件冒泡階段(bubbling phase)。事件從目標(biāo)元素冒泡到document, 依次檢查經(jīng)過的節(jié)點(diǎn)是否綁定了事件監(jiān)聽函數(shù),如果有則執(zhí)行。
事件綁定監(jiān)聽函數(shù)的方式如下:

addEventListener(eventType, handler, useCapture)

事件移除監(jiān)聽函數(shù)的方式如下:

removeEventListener(eventType, handler, useCapture)

Example:

var btn = document.getElementById('.btn');
btn.addEventListener(‘click’, showMessage, false);
btn.removeEventListener(‘click’, showMessage, false);

參數(shù)說明:
eventType指定事件類型(不要加on)
handler是事件處理函數(shù)
useCapture是一個(gè)boolean用于指定是否在捕獲階段進(jìn)行處理,一般設(shè)置為false與IE瀏覽器保持一致。
DOM事件模型中的事件對(duì)象常用屬性:

  • type用于獲取事件類型
  • target獲取事件目標(biāo)
  • stopPropagation()阻止事件冒泡
  • preventDefault()阻止事件默認(rèn)行為
    IE事件模型中的事件對(duì)象常用屬性:
  • type用于獲取事件類型
  • srcElement獲取事件目標(biāo)
  • cancelBubble阻止事件冒泡
  • returnValue阻止事件默認(rèn)行為

Javascript垃圾回收機(jī)制

** 標(biāo)記清除 ** -> 最常見的垃圾回收方式
這是JavaScript最常見的垃圾回收方式,當(dāng)變量進(jìn)入執(zhí)行環(huán)境的時(shí)候,比如函數(shù)中聲明一個(gè)變量,垃圾回收器將其標(biāo)記為“進(jìn)入環(huán)境”,當(dāng)變量離開環(huán)境的時(shí)候(函數(shù)執(zhí)行結(jié)束)將其標(biāo)記為“離開環(huán)境”。垃圾回收器會(huì)在運(yùn)行的時(shí)候給存儲(chǔ)在內(nèi)存中的所有變量加上標(biāo)記,然后去掉環(huán)境中的變量以及被環(huán)境中變量所引用的變量(閉包),在這些完成之后仍存在標(biāo)記的就是要?jiǎng)h除的變量了
** 引用計(jì)數(shù) ** -> 會(huì)出現(xiàn)因?yàn)檠h(huán)引用而出現(xiàn)的無法回收而導(dǎo)致的內(nèi)存泄漏
參考: http://www.lxweimin.com/p/80ed3805edc3

創(chuàng)建對(duì)象的幾種方式

  • ** 使用{}
var bar = {
  color: "blue"
};
  • ** 使用new關(guān)鍵字 **
var bar = new Object();
bar.color = "blue";
  • ** 使用構(gòu)造函數(shù) **
var Fun = function (color) {
  this.color = color;
}
var bar = new Fun();

面向?qū)ο笈c繼承的幾種方式

** 原型編程泛型基本規(guī)則 **

  • 所有的數(shù)據(jù)都是對(duì)象
  • 要得到一個(gè)對(duì)象,不是通過 實(shí)例化類,而是找到一個(gè)對(duì)象作為原型并克隆它
  • 對(duì)象會(huì)記住它的原型
  • 如果對(duì)象本身無法響應(yīng)某個(gè)請(qǐng)求,它會(huì)把這個(gè)請(qǐng)求委托給它自己的原型
    ** 實(shí)現(xiàn)方式 **
    http://www.jb51.net/article/81766.htm

解決跨域問題

Jsonp
Cors
Document.domain
Document.name
HTML5 postMessage

AJAX

創(chuàng)建過程
(1)創(chuàng)建XMLHttpRequest對(duì)象,也就是創(chuàng)建一個(gè)異步調(diào)用對(duì)象.
(2)創(chuàng)建一個(gè)新的HTTP請(qǐng)求,并指定該HTTP請(qǐng)求的方法、URL及驗(yàn)證信息.
(3)設(shè)置響應(yīng)HTTP請(qǐng)求狀態(tài)變化的函數(shù).
(4)發(fā)送HTTP請(qǐng)求.
(5)獲取異步調(diào)用返回的數(shù)據(jù).(6)使用JavaScript和DOM實(shí)現(xiàn)局部刷新.
參考:https://segmentfault.com/a/1190000004322487

說說你對(duì)作用域鏈的理解

作用域鏈的作用是保證執(zhí)行環(huán)境里有權(quán)訪問的變量和函數(shù)是有序的,作用域鏈的變量只能向上訪問,變量訪問到window對(duì)象即被終止,作用域鏈向下訪問變量是不被允許的。

閉包

實(shí)現(xiàn)延遲打印1-5

for (var i = 0; i < 5; i++) {
  (function (i) {
    setTimeout(function () {
      console.log(i)
    }, i * 1000)
  })(i);
}
for (var i = 0; i < 5; i++) {
  setTimeout(function (i) {
    return function() { console.log(i); };
  }(i), i * 1000)
}
[1,2,3,4,5,6].forEach(i => {
    setTimeout(function () {
      console.log(i)
    }, i * 1000);
});

嚴(yán)格模式 (use strict)

  • 非嚴(yán)格模式下有些錯(cuò)誤會(huì)在運(yùn)行時(shí)被悄悄地忽略掉,而在嚴(yán)格模式下,這些錯(cuò)誤會(huì)被拋出來,從而方便debug,通常來說,這是一種很好的實(shí)踐。
  • 防止給未聲明的變量賦值
  • 非嚴(yán)格模式下如果引用的this是null或者undefined的話會(huì)自動(dòng)將this指向global對(duì)象,這種情況會(huì)造成一些比較難發(fā)現(xiàn)且頭疼的bug。而在嚴(yán)格模式下,則會(huì)拋出錯(cuò)誤。
  • 防止在一個(gè)對(duì)象內(nèi)重復(fù)定義屬性。
  • 安全使用eval()
  • delete操作符

如何判讀一個(gè)變量是個(gè)整數(shù) (實(shí)現(xiàn) isInteger(x))

在ES6中,Number.isInteger() 可以用來判斷是否為整數(shù)。
在ES6之前的版本中這個(gè)問題則比較復(fù)雜,因?yàn)閚umberic的值通常是作為一個(gè)浮點(diǎn)數(shù)來存儲(chǔ)的,只能用比較取巧的方式來實(shí)現(xiàn)這樣的判斷邏輯。

function isInteger(x) { return (x^0) === x; }
function isInteger(x) { return Math.round(x) === x; }
function isInteger(x) { 
  return  (typeof x === "number") && (x % 1 === 0;;
}

此外也可以使用parseInt來實(shí)現(xiàn)

function isInteger(x) { return parseInt(x, 10) === x;}

數(shù)組操作 (split, reverse, push, slice, concat)

What will the code below output to the console and why?

var arr1 = "john".split('');
var arr2 = arr1.reverse();
var arr3 = "jones".split('');
arr2.push(arr3);
console.log("array 1: length=" + arr1.length + " last=" + arr1.slice(-1));
console.log("array 2: length=" + arr2.length + " last=" + arr2.slice(-1));

JavaScript 設(shè)計(jì)模式


Angular


雙向綁定如何實(shí)現(xiàn)

臟檢查機(jī)制

React


虛擬DOM 實(shí)現(xiàn)機(jī)制

JQuery


Jquery 綁定事件的方法

target.on("click");
target.click(function() {
});
target.live("click", function () {
});
target.bind("click", function () {
});

#### Jquery的鏈?zhǔn)讲僮魅绾螌?shí)現(xiàn)

# 正則表達(dá)式
****
#### 語法
> https://msdn.microsoft.com/zh-cn/library/ae5bf541(VS.80).aspx

#### 驗(yàn)證身份證
> ```
var reg=/^[1-9]{1}[0-9]{14}$|^[1-9]{1}[0-9]{16}([0-9]|[xX])$/;

面試題


更多面試題: https://www.toptal.com/javascript/interview-questions

鼠標(biāo)點(diǎn)擊頁面中的任意標(biāo)簽,alert標(biāo)簽名稱 (兼容性)

<script type="text/javascript" >
document.onClick() = function(event) {
    var e = event || window.event;
    var src = event.target || event.srcElement;
    alert(src.tagName.toLowercase());
}
</script>

異步加載js方案,不少于兩種

** 同步加載 **

就是我們平時(shí)使用的最多的方式,在頁面中使用script標(biāo)簽
這種模式也叫阻塞模式,會(huì)阻止瀏覽器的后續(xù)處理,停止后續(xù)的解析,只有當(dāng)加載完成,才能進(jìn)行下一步的操作,所以默認(rèn)同步執(zhí)行才是比較安全的。但是這種方式會(huì)造成頁面的阻塞,所以一般建議把<script>標(biāo)簽放在<body>結(jié)尾,這樣盡可能減少頁面阻塞。

** 異步加載 **

異步加載 又叫非阻塞加載,瀏覽器在下載執(zhí)行js的同時(shí),還會(huì)繼續(xù)進(jìn)行后續(xù)頁面的處理。主要有以下幾中方式:

  • ** Script Dom Element **
(function() {
    var scriptEle = document.createElement("script");
    scriptEle.type = "text/javascript";
    scriptEle.async = true;
    scriptEle.src="http://xxx/jquery.js";
    var x = document.getElementByTagName("head")[0];
    x.insertBefore(scriptEle, x.firstChild);
})();

google的使用方式

(function(){;
    var ga = document.createElement('script'); 
    ga.type = 'text/javascript'; 
    ga.async = true; 
    ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js'; 
    var s = document.getElementsByTagName('script')[0]; 
    s.parentNode.insertBefore(ga, s); 
})();

缺點(diǎn): 執(zhí)行完成之前會(huì)阻止onLoad事件的觸發(fā),而現(xiàn)在很多頁面的代碼都會(huì)在onLoad的時(shí)候做一些額外的渲染動(dòng)作,所以還是會(huì)阻塞部分頁面的初始化的處理。

  • ** onload時(shí)的異步加載 **
;(function () {
  if (window.attachEvent) {
    window.attachEvent('load', asyncLoad)
  } else {
    window.addEventListener('load', asyncLoad)
  }
  var asyncLoad = function () {
    var scriptEle = document.createElement('script')
    scriptEle.type = 'text/javascript'
    scriptEle.async = true
    scriptEle.src = 'http://xxx/jquery.js'
    var x = document.getElementByTagName('head')[0]
    x.insertBefore(scriptEle, x.firstChild)
  }
})()

注:DOMContentLoaded與load區(qū)別
前者是在document 已經(jīng)解析完成,頁面中的dom元素可用,但是頁面中的圖片,視頻,音頻等資源還未加載完,作用同jquery的ready. 后者的區(qū)別在于頁面中所有資源包括js都加載完成。

  • ** 其他方法**
    ** XHR Injection **
    通過XMLHttpRequest來獲取javascript,然后創(chuàng)建一個(gè)script元素插入到DOM結(jié)構(gòu)中。ajax請(qǐng)求成功后設(shè)置script.text為請(qǐng)求成功后返回的responseText
var getXmlHttp = function () {
  var obj
  if (window.XMLHttpRequest)
    obj = new XMLHttpRequest()
  else
    obj = new ActiveXObject('Microsoft.XMLHTTP')
  return obj
}
var xhr = getXmlHttp()
xhr.open('GET', 'http://xxx.com/jquery.js', true)
xhr.send()
xhr.onReadyStateChange = function () {
  if (xhr.readyState == 4 && xhr.status == 200) {
    var script = document.createElement('script')
    script.text = xhr.response.text
    document.getElementsByTagName('head')[0].appendChild(script)
  }
}

** XHR Eval **
與XHR Injection對(duì)responseText的執(zhí)行方式不同,直接把responseText放在eval()函數(shù)里面執(zhí)行。
** Script In IFrame **
在父窗口插入一個(gè)iframe元素,然后再iframe中執(zhí)行加載JS的操作。

var insertJS = function(){alert(2)};
    var iframe = document.createElement("iframe");
    document.body.appendChild(iframe);
    var doc = iframe.contentWindow.document;//獲取iframe中的window要用contentWindow屬性。
    doc.open();
    doc.write("<script>var insertJS = function(){};<\/script><body onload='insertJS()'></body>");
    doc.close();
  • ** HTML5新屬性:async和defer屬性 **
    ** defer屬性 **:IE4.0就出現(xiàn)。defer屬聲明腳本中將不會(huì)有document.write和dom修改。瀏覽器會(huì)并行下載其他有defer屬性的script。而不會(huì)阻塞頁面后續(xù)處理。注:所有的defer腳本必須保證按順序執(zhí)行的。
<script type="text/javascript" defer></script>

** async屬性 **:HTML5新屬性。腳本將在下載后盡快執(zhí)行,作用同defer,但是不能保證腳本按順序執(zhí)行。他們將在onload事件之前完成。

<script type="text/javascript" defer></script>

Firefox 3.6、Opera 10.5、IE 9和最新的Chrome和Safari都支持async屬性。可以同時(shí)使用async和defer,這樣IE 4之后的所有IE都支持異步加載。
沒有async屬性,script將立即獲?。ㄏ螺d)并執(zhí)行,期間阻塞了瀏覽器的后續(xù)處理。如果有async屬性,那么script將被異步下載并執(zhí)行,同時(shí)瀏覽器繼續(xù)后續(xù)的處理。


** 總結(jié) **: 對(duì)于支持HTML5的瀏覽器,實(shí)現(xiàn)JS的異步加載只需要在script元素中加上async屬性,為了兼容老版本的IE還需加上defer屬性;對(duì)于不支持HTML5的瀏覽器(IE可以用defer實(shí)現(xiàn)),可以采用以上幾種方法實(shí)現(xiàn)。原理基本上都是向DOM中寫入script或者通過eval函數(shù)執(zhí)行JS代碼,你可以把它放在匿名函數(shù)中執(zhí)行,也可以在onload中執(zhí)行,也可以通過XHR注入實(shí)現(xiàn),也可以創(chuàng)建一個(gè)iframe元素,然后在iframe中執(zhí)行插入JS代碼。

設(shè)計(jì)一種方案,確保頁面中所有js加載完全

function loadScript (url, callback) {
var script = document.createElement('script')
script.type = 'text/javascript'
if (script.readyState) {
script.onreadystatechange = function () {
if (script.readyState == 'loaded' || script.readyState == 'complete') {
script.onreadystatechange = null
callback()
}
}
} else {
script.onload = function () {
callback()
}
}
script.src = url
document.getElementsByName('head')[0].appendChild(script)
}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,936評(píng)論 6 535
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,744評(píng)論 3 421
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,879評(píng)論 0 381
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,181評(píng)論 1 315
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,935評(píng)論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,325評(píng)論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,384評(píng)論 3 443
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,534評(píng)論 0 289
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,084評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,892評(píng)論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,067評(píng)論 1 371
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,623評(píng)論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,322評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,735評(píng)論 0 27
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,990評(píng)論 1 289
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,800評(píng)論 3 395
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,084評(píng)論 2 375

推薦閱讀更多精彩內(nèi)容