JQuery另類視角-動態執行指令碼的BUG

來源:互聯網
上載者:User

  最近再用JQuery寫一些東西,昨天突然出了個很奇怪的問題:

  我通過Ajax請求伺服器上的資料(包括html和script),然後將請求的資料動態載入到頁面的一個div中,這其實是個很簡單的程式,首次執行是很順利,但是當你執行這個相同動作兩次之後,html元素依然可以順利載入,不過script指令碼就失效了!

  使用的是JQuery的1.4.1版本,載入的程式是用JQuery中的$(...).append()方法。類試代碼如下:

$("#testdiv").append("<script type='text/javascript'> a = 1 ;alert(a);" + "<" + "/script>");

  你執行後會發現,前兩次能很成功的彈出提示框,但是從第三次開始就失效了!

  為什嗎?javascript本身不可能不支援這種程式的,難道是JQuery程式的BUG嗎?!是的,該BUG已經在1.4.2版本中進行了修複,你可以換成JQuery-1.4.2版本來試下。真是鬱悶,這個問題害的我查了一個晚上才發現.....

  下面讓我們分析下這個BUG的原因:

   首先看下append函數中主要的執行流程,

  

 

  執行script指令碼的程式是在domManip函數中,大概的邏輯如下:

  導致該問題的函數是buildFragment函數,對比下該函數在這兩個版本的代碼,

jquery-1.4.1

function buildFragment( args, nodes, scripts ) {
    var fragment, cacheable, cacheresults, doc;

    // webkit does not clone 'checked' attribute of radio inputs on cloneNode, so don't cache if string has a checked
    if (args.length === 1 && typeof args[0] === "string" && args[0].length < 512 && args[0].indexOf("<option") < 0 
        && (jQuery.support.checkClone || !rchecked.test( args[0] )) ) {
        cacheable = true;
        cacheresults = jQuery.fragments[ args[0] ];
        if ( cacheresults ) {
            if ( cacheresults !== 1 ) {
                fragment = cacheresults;
            }
        }
    }

    if ( !fragment ) {
        doc = (nodes && nodes[0] ? nodes[0].ownerDocument || nodes[0] : document);
        fragment = doc.createDocumentFragment();
        jQuery.clean( args, doc, fragment, scripts );
    }

    if ( cacheable ) {
        jQuery.fragments[ args[0] ] = cacheresults ? fragment : 1;
    }

    return { fragment: fragment, cacheable: cacheable };
}jquery-1.4.2

function buildFragment( args, nodes, scripts ) {
    var fragment, cacheable, cacheresults,
        doc = (nodes && nodes[0] ? nodes[0].ownerDocument || nodes[0] : document);

    // Only cache "small" (1/2 KB) strings that are associated with the main document
    // Cloning options loses the selected state, so don't cache them
    // IE 6 doesn't like it when you put <object> or <embed> elements in a fragment
    // Also, WebKit does not clone 'checked' attributes on cloneNode, so don't cache
    if ( args.length === 1 && typeof args[0] === "string" && args[0].length < 512 && doc === document &&
        !rnocache.test( args[0] ) && (jQuery.support.checkClone || !rchecked.test( args[0] )) ) {

        cacheable = true;
        cacheresults = jQuery.fragments[ args[0] ];
        if ( cacheresults ) {
            if ( cacheresults !== 1 ) {
                fragment = cacheresults;
            }
        }
    }

    if ( !fragment ) {
        fragment = doc.createDocumentFragment();
        jQuery.clean( args, doc, fragment, scripts );
    }

    if ( cacheable ) {
        jQuery.fragments[ args[0] ] = cacheresults ? fragment : 1;
    }

    return { fragment: fragment, cacheable: cacheable };
}

   仔細看完這兩段代碼後,會發現這個函數內設定scripts的程式是jQuery.clean( args, doc, fragment, scripts ),這行代碼在執行之前有個判斷:如果該傳入的指令碼資料允許支援緩衝,並且資料在緩衝jQuery.fragments中存在,那麼這行代碼是跳過的!否則,該行代碼執行,設定scripts資料。

  現在把關注點放到"允許支援緩衝"這句話上,比較這兩個版本對於該程式的不同。!rnocache.test( args[0] ),這是1.4.2版本中多加的一行代碼。終於找到它,它是這個BUG解決的關鍵所在。讓我們看下這個rnocache的Regex:

rnocache = /<script|<object|<embed|<option|<style/i,

 

   看了這麼多發現原因了嗎!原來1.4.1版本會對script指令碼進行緩衝,一旦script緩衝在指令碼後,該指令碼中的程式是不會執行的,而1.4.2多加了上面的正則,目的就是對script等這些資料不進行緩衝,只要存在就會去執行!

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.