Темы



[Перевод] Удивительная история document.write

Метод document.write — один из самых странных методов. Он вставляет HTML-код на страницу сразу после себя. Точнее говоря, сразу после тега <script>, внутри которого он расположен. И только в том случае, если документ еще не был загружен полностью. А если был? Тогда страница очищается и заменяется на, что было указано.

Можно вставить строку, которая явно сломает остальную страницу:

document.write('')
</code></pre><br />
Или&nbsp;можно поиграть в&nbsp;русскую рулетку: <pre><code class="javascript">if (Math.random() > 0.9)
  document.write('<!--')
</code></pre><br />
Оказывается, тот факт, что&nbsp;текст вставляется сразу <i>после</i> тега <code>&lt;script></code>&nbsp;— это важно. Например: <pre><code class="javascript">&lt;script>
  document.write('&lt;script src="jquery.js"></' + 'script>');
  alert(jQuery.guid)
&lt;/script&gt;
</code></pre><br />
Данный код выведет ошибку о&nbsp;том, что&nbsp;переменная jQuery не&nbsp;объявлена.<br />
С&nbsp;другой стороны: <pre><code>&lt;script>
  document.write('&lt;script src="jquery.js"></' + 'script>');
&lt;/script&gt;
&lt;script>
  alert(jQuery.guid)
&lt;/script&gt;
</code></pre><br />
А&nbsp;этот код выполнится без&nbsp;ошибок, потому что&nbsp;второй тег <code>&lt;script></code> не&nbsp;начнет исполняться до&nbsp;тех пор, пока не&nbsp;будет полностью обработан скрипт, подгруженный из&nbsp;первого тега.<p>Дальше становится все любопытнее. Представим, что&nbsp;есть такой код: </p><pre><code class="javascript">&lt;script>
  console.log('a');
  document.write('&lt;script src="printC.js"></' + 'script>');
  console.log('b');
&lt;/script&gt;
&lt;script>
  console.log('d');
&lt;/script&gt;
</code></pre><br />
А&nbsp;в&nbsp;файле <code>printC.js</code> содержится следующее: <pre><code class="javascript">console.log('c')
</code></pre><br />
Данный код выведет в&nbsp;консоль следующее: <pre><code class="javascript">a
b
c
d
</code></pre><br />
Из&nbsp;этого примера видно, что&nbsp;весь код из&nbsp;первого тега <code>&lt;script></code> после <code>document.write</code> был выполнен сразу же, а&nbsp;вот <i>второй</i> тег начал исполняться только после того, как&nbsp;завершил свою работу <code>printC.js</code>.<p>Следует помнить. что&nbsp;этот способ вставки контента работает только непосредственно во&nbsp;время загрузки документа. Что&nbsp;будет, если вызвать <code>document.write</code> после того, как&nbsp;он уже загружен? Было бы логично выдать ошибку, или&nbsp;не&nbsp;делать ничего. Вместо этого вся существующая страница стирается, а&nbsp;на&nbsp;ее место выводится переданная строка: </p><pre><code class="javascript">setTimeout(function(){
  document.write("Oops");
})
</code></pre><br /><h3>Существует ли нормальный повод применять <code>document.write</code>? </h3><br />
Я&nbsp;о&nbsp;таком не&nbsp;слышал. По&nbsp;всей видимости, он используется в&nbsp;баннерокрутилках, потому что&nbsp;позволяет показать отслеживающую картинку вместо AJAX-запроса, если пользователь заходит на&nbsp;сайт через&nbsp;Netscape 2. В&nbsp;современном же мире он особо ни&nbsp;для&nbsp;чего не&nbsp;нужен.<p>Правда, иногда встречаются замечательные инструменты, которые незаметно оборачивают передаваемый вами HTML в&nbsp;вызовы <code>document.write</code>.</p><h3>Можно ли вызвать <code>document.write</code> внутри <code>document.write</code>? </h3><br />
Ага! <h3>Типа, бесконечно много раз? </h3><br />
Нет, 20 раз.<h3>Серьезно? Двадцать? </h3><br />Ага.<p>Google Chrome, несомненно, более совершенный браузер&nbsp;— там&nbsp;можно аж 21 раз.</p><h3>Они что, независимо друг от&nbsp;друга до&nbsp;этого додумались? </h3><br />
Разработчики Firefox первыми исправили баг, потенциально позволявший уронить браузер, а&nbsp;разработчики Webkit скопировали их&nbsp;решение. Ходят слухи, что&nbsp;в&nbsp;IE тоже есть некий предел, но&nbsp;он еще ниже.<h3>Можно ли сломать браузер еще быстрее? </h3><br /><pre><code class="javascript"><div id="uniqid">
  &lt;script language="JavaScript" type="text/JavaScript">
    document.write(">"+document.getElementById('uniqid').innerHTML+"<");
  &lt;/script&gt;
</div>
</code></pre><br />
(Код взят из&nbsp;тикета)<h3>Какие еще глупости можно натворить с&nbsp;<code>document.write</code>? </h3><br />
Да&nbsp;какие угодно! <p>Например, можно сделать <i>синхронный</i> AJAX-запрос и&nbsp;вставить его результат непосредственно в&nbsp;тело страницы: </p><pre><code class="javascript">x = new XMLHttpRequest()
x.open('GET', "", false)
x.send()
document.write(x.responseText);
</code></pre><br />
Отправка запроса заблокирует загрузку основной страницы, и&nbsp;содержимое ответа будет вставлено так, как&nbsp;если бы оно изначально располагалось на&nbsp;загружаемой странице. В&nbsp;данном случае вместо URL передана пустая строка, поэтому загружаться будет та же самая страница, а&nbsp;она, в&nbsp;свою очередь, снова начнет загружать сама себя, и&nbsp;так до&nbsp;бесконечности*.<p>* Под&nbsp;«до&nbsp;бесконечности» подразумевается 20 раз. Или&nbsp;21. Или&nbsp;еще меньше, если вы в&nbsp;IE.</p><p>В&nbsp;общем, можно развлекаться по-разному.</p><h3>Что-нибудь еще? </h3><br />
В&nbsp;текущей спецификации этого нет (хотя было в&nbsp;прошлых версиях), но&nbsp;можно передавать в&nbsp;<code>document.write</code> несколько параметров, например: <pre><code class="javascript">document.write("П", "Р", "Е", "В", "Е", "Д");
</code></pre><br /><h3>Если метод бесполезен, зачем я&nbsp;про&nbsp;него вообще читаю? </h3><br />
А&nbsp;вот это действительно хороший вопрос! <p><i>Примечание переводчика: </i></p><p>Любопытно, что&nbsp;если что&nbsp;только <i>первый</i> вызов <code>document.write</code> после загрузки страницы очищает ее содержимое. Последующие вызовы дописывают текст после первого.</p></div>

<div>
 <h2>
 Комментарии (<span>5</span>)
 
 </h2>

 

 

 <ul><li class="comment_item"><p>
 
 </p>

<div>
 <div>

 

<p><span class="comment-item__user-info">
 
 
 
 schroeder
 </span></p>

<p>
 10 июля 2016 в&nbsp;19:02
 </p>

<div>

 <div>
 <span class="voting-wjt__counter-score js-score">–4</span>
 </div>

<p><span>↑</span></p>

<p><span>↓</span>
 </p></div>
 </div>

 <div>
 позвольте ламерский вопрос: <br />
, а&nbsp;что&nbsp;значит «когда страница загружена»? Как&nbsp;определяется, что&nbsp;страница загружена?
 </div>

 

 
 </div>

 <ul><li class="comment_item"><p>
 
 </p>

<div>
 <div>

 

<p><span class="comment-item__user-info">
 
 
 
 Vindicar
 </span></p>

<p>
 10 июля 2016 в&nbsp;19:17
 </p>

<div>

 <div>
 <span class="voting-wjt__counter-score js-score">0</span>
 </div>

<p><span>↑</span></p>

<p><span>↓</span>
 </p></div>
 </div>

 <div>
 Я&nbsp;полагаю, после отработки события onLoad?
 </div>

 

 
 </div>

 </li>

 <li class="comment_item"><p>
 
 </p>

<div>
 <div>

 

<p><span class="comment-item__user-info">
 
 <img src="https://habrastorage.org/getpro/habr/avatars/7ee/22a/b94/7ee22ab9492fc66bb567d974fcfcf095_small.png" alt=""  />
 impwx
 </span></p>

<p>
 10 июля 2016 в&nbsp;19:38
 </p>

<div>

 <div>
 <span class="voting-wjt__counter-score js-score">0</span>
 </div>

<p><span>↑</span></p>

<p><span>↓</span>
 </p></div>
 </div>

 <div>
 Если не&nbsp;ошибаюсь, страница считается загруженной, когда браузер получил ее код от&nbsp;сервера целиком и&nbsp;построил по&nbsp;нему DOM. Пользователь может отследить этот момент, как&nbsp;правильно сказал Vindicar, по&nbsp;событию <code>onLoad</code>, или&nbsp;с&nbsp;помощью более удобного синтаксиса у&nbsp;jQuery.
 </div>

 

 
 </div>

 <ul><li class="comment_item"><p>
 
 </p>

<div>
 <div>

 

<p><span class="comment-item__user-info">
 
 <img src="https://habrastorage.org/getpro/habr/avatars/722/0f3/5c4/7220f35c4b3ba6aa298c92d7999e1a8a_small.png" alt=""  loading="lazy" decoding="async" />
 heilage
 </span></p>

<p>
 10 июля 2016 в&nbsp;19:53
 </p>

<div>

 <div>
 <span class="voting-wjt__counter-score js-score">0</span>
 </div>

<p><span>↑</span></p>

<p><span>↓</span>
 </p></div>
 </div>

 <div>
 То, что&nbsp;вы описали&nbsp;— это DOMContentLoaded, событие Load срабатывает при&nbsp;полной обработке всех ресурсов страницы. Однако, в&nbsp;таких ненормальных условиях, как&nbsp;наличие document.write непосредственно в&nbsp;script-теге, возможно существует и&nbsp;какое-то&nbsp;иное поведение.
 </div>

 

 
 </div>

 </li>

 
 </ul></li>

 
 </ul></li>

 <li class="comment_item"><p>
 
 </p>

<div>
 <div>

 

<p><span class="comment-item__user-info">
 
 <img src="https://habrastorage.org/getpro/habr/avatars/1a3/e94/70a/1a3e9470a1ac25ffa47637a8439817ef_small.jpg" alt=""  loading="lazy" decoding="async" />
 artyfarty
 </span></p>

<p>
 10 июля 2016 в&nbsp;19:59
 </p>

<div>

 <div>
 <span class="voting-wjt__counter-score js-score">0</span>
 </div>

<p><span>↑</span></p>

<p><span>↓</span>
 </p></div>
 </div>

 <div>
 полезно еще знать, что&nbsp;есть document.close (), который по-хорошему стоит вызывать после document.write, иначе некоторые браузеры будут показывать крутилку «загрузки».
 </div>

 

 
 </div>

 </li>

 
 </ul></div>
    
            <p class="copyrights"><span class="source">&copy;&nbsp;<a target="_blank" rel="nofollow" href="https://habrahabr.ru/post/305366/">Habrahabr.ru</a></span></p>
                                        </div>
                                                    
            <br>
            <!--<div align="left">
                <script type="text/topadvert">
                load_event: page_load
                feed_id: 12105
                pattern_id: 8187
                tech_model:
                </script><script type="text/javascript" charset="utf-8" defer="defer" async="async" src="//loader.topadvert.ru/load.js"></script>
            </div>
            <br>-->

            <div style="padding-left: 20px;">
                <!-- PCNews 336x280 -->

            </div>

        </div>

        <br class="clearer"/>

        <br class="clearer"/>
    </div>
    <br class="clearer"/>

    

        <div id="footer-2nd"></div>

        <div id="footer">
            <br/><br/>
            <ul class="horz-menu">
                <li class="about"><a href="/info/about.html" title="О проекте">О
                        проекте</a></li>
                <li class="additional-menu"><a href="/archive.html" title="Архив материалов">Архив</a>
                </li>
                <li class="additional-menu"><a href="/info/reklama.html"
                                               title="Реклама" class="menu-item"><strong>Реклама</strong></a>
                    <a href="/info/partners.html" title="Партнёры"
                       class="menu-item">Партнёры</a>
                    <a href="/info/legal.html" title="Правовая информация"
                       class="menu-item">Правовая информация</a>
                    <a href="/info/contacts.html" title="Контакты"
                       class="menu-item">Контакты</a></li>
                <li class="email"><a href="mailto:pcnews@pcnews.ru" title="Пишите нам на pcnews@pcnews.ru"><img
                                src="/media/i/email.gif" alt="e-mail"/></a></li>
                <li style="visibility: hidden">
                    <noindex>
                        <!-- Rating@Mail.ru counter -->
                        <script type="text/javascript">
                            var _tmr = window._tmr || (window._tmr = []);
                            _tmr.push({id: "93125", type: "pageView", start: (new Date()).getTime()});
                            (function (d, w, id) {
                                if (d.getElementById(id)) return;
                                var ts = d.createElement("script");
                                ts.type = "text/javascript";
                                ts.async = true;
                                ts.id = id;
                                ts.src = (d.location.protocol == "https:" ? "https:" : "http:") + "//top-fwz1.mail.ru/js/code.js";
                                var f = function () {
                                    var s = d.getElementsByTagName("script")[0];
                                    s.parentNode.insertBefore(ts, s);
                                };
                                if (w.opera == "[object Opera]") {
                                    d.addEventListener("DOMContentLoaded", f, false);
                                } else {
                                    f();
                                }
                            })(document, window, "topmailru-code");
                        </script>
                        <noscript>
                            <div style="position:absolute;left:-10000px;">
                                <img src="//top-fwz1.mail.ru/counter?id=93125;js=na" style="border:0;" height="1"
                                     width="1" alt="Рейтинг@Mail.ru"/>
                            </div>
                        </noscript>
                        <!-- //Rating@Mail.ru counter -->

                    </noindex>
                </li>
            </ul>
        </div>

        <!--<div id="robot-image"><img class="rbimg" src="i/robot-img.png" alt="" width="182" height="305" /></div>-->

    </div>



    <div id="footer-adlinks"></div>

    
    
    
        <noindex>


            

            <!-- Rating@Mail.ru counter -->
            <script type="text/javascript">
                var _tmr = window._tmr || (window._tmr = []);
                _tmr.push({id: "93125", type: "pageView", start: (new Date()).getTime()});
                (function (d, w, id) {
                    if (d.getElementById(id)) return;
                    var ts = d.createElement("script"); ts.type = "text/javascript"; ts.async = true; ts.id = id;
                    ts.src = "https://top-fwz1.mail.ru/js/code.js";
                    var f = function () {var s = d.getElementsByTagName("script")[0]; s.parentNode.insertBefore(ts, s);};
                    if (w.opera == "[object Opera]") { d.addEventListener("DOMContentLoaded", f, false); } else { f(); }
                })(document, window, "topmailru-code");
            </script><noscript><div>
                    <img src="https://top-fwz1.mail.ru/counter?id=93125;js=na" style="border:0;position:absolute;left:-9999px;" alt="Top.Mail.Ru" />
                </div></noscript>
            <!-- //Rating@Mail.ru counter -->



            <!-- Yandex.Metrika counter -->
            <script type="text/javascript">
                (function(m,e,t,r,i,k,a){
                    m[i]=m[i]||function(){(m[i].a=m[i].a||[]).push(arguments)};
                    m[i].l=1*new Date();
                    for (var j = 0; j < document.scripts.length; j++) {if (document.scripts[j].src === r) { return; }}
                    k=e.createElement(t),a=e.getElementsByTagName(t)[0],k.async=1,k.src=r,a.parentNode.insertBefore(k,a)
                })(window, document,'script','https://mc.yandex.ru/metrika/tag.js', 'ym');

                ym(23235610, 'init', {webvisor:true, clickmap:true, referrer: document.referrer, url: location.href, accurateTrackBounce:true, trackLinks:true});
            </script>
            <noscript><div><img src="https://mc.yandex.ru/watch/23235610" style="position:absolute; left:-9999px;" alt="" /></div></noscript>
            <!-- /Yandex.Metrika counter -->

            <!-- Default Statcounter code for PCNews.ru https://pcnews.ru-->
            <script type="text/javascript">
                var sc_project=9446204;
                var sc_invisible=1;
                var sc_security="14d6509a";
            </script>
            <script type="text/javascript"
                    src="https://www.statcounter.com/counter/counter.js"
                    async></script>
            <noscript><div class="statcounter"><img class="statcounter"
                src="https://c.statcounter.com/9446204/0/14d6509a/1/"
                alt="Web Analytics"
                referrerPolicy="no-referrer-when-downgrade"></div></noscript>
            <!-- End of Statcounter Code -->

            <script>
                (function (i, s, o, g, r, a, m) {
                    i['GoogleAnalyticsObject'] = r;
                    i[r] = i[r] || function () {
                            (i[r].q = i[r].q || []).push(arguments)
                        }, i[r].l = 1 * new Date();
                    a = s.createElement(o),
                        m = s.getElementsByTagName(o)[0];
                    a.async = 1;
                    a.src = g;
                    m.parentNode.insertBefore(a, m)
                })(window, document, 'script', '//www.google-analytics.com/analytics.js', 'ga');

                ga('create', 'UA-46280051-1', 'pcnews.ru');
                ga('send', 'pageview');

            </script>

            <script async="async" src="/assets/uptolike.js?pid=49295"></script>

        </noindex>
    



<!--<div id="AdwolfBanner40x200_842695" ></div>-->
<!--AdWolf Asynchronous Code Start -->

<script type="text/javascript" src="https://pcnews.ru/js/blockAdblock.js"></script>

<script type="text/javascript" src="/assets/jquery-3.7.1.min.js"></script>
<script type="text/javascript" src="/assets/jquery-migrate-3.5.2.min.js"></script>
<script type="text/javascript" src="/assets/b586b5e/jquery/jquery.form-4.3.0.js?v=8cec94ac0f"></script>
<script type="text/javascript" src="/assets/b586b5e/js/browser-sniff.js?v=e72898e78a"></script>
<script type="text/javascript" src="/assets/b586b5e/js/scripts.js?v=355b3d117d"></script>
<script type="text/javascript" src="/assets/b586b5e/js/pcnews-utils.js?v=cd3bda5bb1"></script>
<script type="text/javascript" src="/assets/b586b5e/js/pcnews-auth.js?v=b89035a38f"></script>
<script type="text/javascript" src="/assets/b586b5e/js/pcnews-mobile.js?v=f0d032cb6b"></script>
<script type="text/javascript" src="/assets/b586b5e/js/pcnews-fiximg.js?v=5071165dc0"></script>
<script type="text/javascript" src="/assets/b586b5e/js/pcnews-infobox.js?v=d7b0fbb0df"></script>
</body>
</html>