天天看點

document.write什麼時候會清除文檔内容?

在調用document.write時,會将内容寫入文檔流,是以會自動調用document.open方法打開文檔流,如果文檔流已經關閉,則會清除所有内容。

那什麼時候代表文檔流已經關閉呢?即所有的内容都已經讀入到浏覽器中(含所有的内聯CSS、HTML标簽),即頁面的主線程沒有執行完成,也就是我們所看到的源代碼裡面的所有内容。

以如下的代碼為例:

<body>
    <h1>Hello, World!</h1>
    <script type="text/javascript">
        document.write('<h2>Hello, Yiifaa!</h2>')
    </script>
</body>
           

因為此時頁面的主線程沒有執行完成,是以會将“

Hello, Yiifaa!

”添加到文檔末尾,但如果利用setTimeout暫時放棄主線程的執行,切換到任務隊列中,那麼随着文檔流的寫入結束,此時需要重新打開文檔流,那麼文檔的内容則會全部覆寫,如下:

<body>
    <h1>Hello, World!</h1>
    <script type="text/javascript">
        //  暫時放棄主線程的執行
        setTimeout(function() {
            document.write('<h2>Hello, Yiifaa!</h2>')
        }, );
    </script>
</body>
           

通過上面的例子可以看出,隻要浏覽器解析到文檔末尾,則浏覽器主線程結束,文檔流關閉。

需要特别指出的,文檔是嚴格按照從下直下的順序執行的,即使某一個js由于網絡原因延遲了較長時間,那麼文檔也會一直等待它的執行,直到逾時或等待的JS執行完成,進而将浏覽器主線程的執行周期拉長。

模拟JS延時的代碼如下(jsp實作):

<%@ page language="java" contentType="text/javascript; charset=UTF-8" pageEncoding="UTF-8"%>
<%
    Thread.sleep();
%>
//  業務處理代碼
alert('defered script!');
           

順帶說一個document.write産生的安全現象,如果在document.write寫入的内容請求了其他的JS檔案,會提示跨站腳本攻擊:

A Parser-blocking, cross site (i.e. different eTLD+) script,
http://localhost/mirana-birt/defered.jsp, is invoked via document.write. 
The network request for this script MAY be blocked by the browser in this or a future page load due to poor network connectivity. If blocked in this page load, it will be confirmed in a subsequent console message.
           

示例代碼如下:

document.write('<script src="http://localhost/mirana-birt/defered.jsp"><\/script>')
setTimeout(function() {
    document.write('<h2>Hello, Yiifaa!</h2>')
}, )
           

更有意思的是,IE浏覽器與Chrome表現出截然不同的表現,IE會直接抹掉所有内容,并會取消所有未完成的請求。

另,在文檔流的寫入過程,由于JS單線程的限制,document.close()并不能真正關閉流,隻能起到一個代碼标記的作用,如下面的代碼,并不會清除文檔内容,說明文檔流并沒有關閉:

<body>
    <h1>Hello, World!</h1>
    <script type="text/javascript">

        document.close()
        document.write('Hello, Yiifaa!')
    </script>
 </body>
           

結論

document.write的寫入效果跟文檔流所處的狀态嚴格相關,如果文檔流已關閉,則必然會出現清除文檔内容的現狀。

繼續閱讀