`document.write`是否适合查找与当前正在运行的脚本相关联的元素? [英] Is `document.write` suitable for finding the element associated with the currently running script?

查看:86
本文介绍了`document.write`是否适合查找与当前正在运行的脚本相关联的元素?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何找到与当前正在运行的脚本相关联的脚本元素?我只对文档正文中的脚本感兴趣,而不是头部(或其他位置)中的脚本。



这是我到目前为止,它似乎工作好的。有没有任何可能的陷阱我不在想?

  function getCurrentScriptElement(){
var placeholderId ='placeholder - '+ Math.random(),
脚本,占位符
document.write('< br id ='+ placeholderId +'>');
placeholder = document.getElementById(placeholderId);
script = placeholder.previousSibling;
placeholder.parentNode.removeChild(placeholder);
返回脚本;
}

我想到的这个用例涉及需要注入内容的脚本在发生脚本标记的文档中的相同位置,因此延迟加载将不会成为问题。换句话说,我只会在适当的地方调用这个函数,它不会被暴露为API或任何东西的一部分。



我也知道问题 document.write 和XHTML,在这种情况下,我并不担心(到目前为止)。






尝试看起来像这样:

  function getCurrentScriptElement(){
var scripts = document.getElementsByTagName('script') ;
返回脚本[scripts.length - 1];
}

但是,正如我们在这个问题,如果另一个脚本被注入到文档中,这可能会很容易失败。






我还在这个 document.currentScript work / multipage / dom.html#dom-document-currentscriptrel =nofollow noreferrer> WHATWG spec 。在这一点上似乎没有得到广泛的支持。 document.currentScript 有一个有趣的垫片,它需要另一个路径 ...脚本触发错误,捕获它,检查堆栈跟踪以查找脚本的URL,然后找到具有匹配的脚本元素 src 属性



这是一个聪明的解决方案,但它显然不会在IE中运行,如果几个脚本使用相同的URL。






理想情况下,我想找到一个解决方案,提供与顶级代码示例相同的结果额外要求),但不依赖于 document.write 。这可能吗?如果没有,这个代码是否相当安全,假设它正确使用(仅在页面加载,而不是XHTML)?






编辑:有关另一个潜在用例,请参见此答案,以及为什么 br 元素用于占位符。

解决方案

OP有一个很好的解决方案来解决棘手的问题。但是,这里有一些小的改进建议。



如果可用,该函数应该使用document.currentScript。无论情况如何,它都能很好地工作。可用于FireFox +4,Chrome +29和Opera +16。



使用IE 6-10,script.readyState可用于模拟document.currentScript。为了避免出现问题,当document.readyState ==完成或者甚至在较早的交互式时,该函数应该退出,否则这个函数似乎可以很好地运行。



<阶段取决于代码。 document.currentScript在完成时似乎停止工作。但是,document.write在交互式中停止,即使用懒惰的脚本,找到脚本的标签写入方法将失败。



脚本异步属性应该被检查之前使用document.write()。标记为异步的脚本与文档分离,并且document.write()方法将无法正常工作。



OP的代码写入< p>标签,但是样式标签似乎在身体和头部的脚本中都能更好地工作,而没有副作用。



随机数字标签ID似乎不从元素删除以来,服务于很多目的。可能会更好地使用重复使用的GUID常数。



更新:



我已经更新了我的下面的代码示例来说明一个方法,而不需要写标签。 Chrome,FireFox,Opera和IE 5-10可以正常工作。无论注入的脚本和脚本属性(延迟和异步)如何,返回正确的值。 IE +11有什么困难的部分? Microsoft在IE11中删除了script.readyState,而无需提供其他选项。一个解决方法是使用MutationObserver来展望脚本。在IE中,这些事件事件发生在脚本执行之前(与之前发生的onload相反)。除非有外部加载的脚本具有延迟或异步属性设置,否则这样做很好。异步脚本特别困难,因为它们可以随时执行,而不是始终按照相同的顺序执行(我的观察)。



无论如何,我以为我会发布这个代码,希望它可以提供一个起点,帮助别人。



参考文献:



https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver



http://msdn.microsoft.com/en-us/library /ie/dn265034(v=vs.85).aspx



CODE SNIPPET:

  var currentScript =(function(){

// PRIVATE
var observer,current,nodes;

// IE + 11 - 未经测试的其他浏览器
if(!document.currentScript&& typeof MutationObserver =='function'){
observer = new MutationObserver(function ){
if(document.readyState =='complete')观察er.disconnect();
mutations.forEach(function(mutation){
nodes = mutation.addedNodes;
if(nodes.length&& nodes [0] .nodeName =='SCRIPT'){
current = nodes [0];
}
});
});
observer.observe(window.document,{childList:true,subtree:true});
}

// PUBLIC
return function(){

if(document.readyState =='complete')return;

// CHROME + 29,FIREFOX + 4,OPERA + 16
if(document.currentScript)return document.currentScript;

var i,s = document.getElementsByTagName('SCRIPT');

// MSIE + 5-10
if(s [0] .readyState)
for(i = 0; i< s.length; i ++)
if(s [i] .readyState =='interactive')return s [i];

// IE + 11
if(current)return current;

// BEST GUESS
return s [s.length-1];

}

})()


How can I find the script element associated with the currently running script? I'm only interested in scripts inside the body of the document, not in the head (or elsewhere).

Here is what I have so far, it seems to work alright. Are there any possible pitfalls I'm not thinking of?

function getCurrentScriptElement() {
    var placeholderId = 'placeholder-' + Math.random(), 
        script, placeholder;
    document.write('<br id="' + placeholderId + '">');
    placeholder = document.getElementById(placeholderId);
    script = placeholder.previousSibling;
    placeholder.parentNode.removeChild(placeholder);
    return script;
}

The use case I have in mind for this involves scripts that need to inject content at the same place in the document where the script tag occurs, so delayed loading will not be an issue. In other words I will only be calling this function in places where it's appropriate, it's not going to be exposed as part of an API or anything.

I'm also aware of the problem with document.write and XHTML, and am not worried about it in this case (so far).


My previous attempt looked something like this:

function getCurrentScriptElement() {
    var scripts = document.getElementsByTagName('script');
    return scripts[scripts.length - 1];
}

But, as we see in this question, this could easily fail if another script has been injected into the document.


I also found document.currentScript in this WHATWG spec. It doesn't seem to be widely supported at this point. There's an interesting shim for document.currentScript that takes another route... The script triggers an error, catches it, inspects the stack trace to find the URL of the script, and then finds the script element with the matching src attribute.

It's a clever solution, but it apparently won't work in IE, and it would break if several scripts use identical URLs.


Ideally, I would like to find a solution that gives the same result as the top code sample (no extra requirements), but doesn't rely on document.write. Is this possible? If not, is this code fairly safe assuming it's used correctly (only during page load, not XHTML)?


Edit: See this answer for another potential use case, and details on why a br element is used for the placeholder.

解决方案

OP has a good solution to a tricky problem. Yet, here are few minor suggestions to improve it.

The function should use document.currentScript when available. It works well regardless of situation. Available in FireFox +4, Chrome +29, and Opera +16.

With IE 6-10 the script.readyState can be used to emulate document.currentScript. It also appears to work well regardless of situation.

To avoid problems, the function should exit when document.readyState == "complete" or even at the earlier "interactive" stage depending on the code. document.currentScript appears to stop working when "complete". However, document.write stops at "interactive", i.e., the tag writing method of finding scripts will fail with a lazy loaded script.

The script async attribute should be checked before using document.write(). Scripts marked async are detached from the document and document.write() method will not work as expected.

OP's code writes a <p> tag, but a style tag appeared to work better with scripts in both the body and head ... and without side effects.

The random number tag ID doesn't seem to serve much purpose since the element is removed. Might be better to go with a GUID constant that's reused.

UPDATE:

I've updated my code sample below to illustrate a way to do this without writing tags. It appears to work fine with Chrome, FireFox, Opera, and IE 5-10. Returns the correct value regardless of injected scripts and script attributes (defer and async). The difficult part is what to do about IE +11? Microsoft removed script.readyState in IE11 without providing an alternative. One workaround is to use "MutationObserver" to look ahead for scripts. In IE these events events happen each time before a script is executed (as opposed to onload which happens afterward). And this works well except when there are externally loaded scripts with defer or async attributes set. Async scripts are especially difficult because they can execute anytime and not always in the same order (my observation).

Anyway, I thought I'd post this code with the hope it might provide a starting point and help others out.

References:

https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver

http://msdn.microsoft.com/en-us/library/ie/dn265034(v=vs.85).aspx

CODE SNIPPET:

    var currentScript = (function() {

        // PRIVATE
        var observer, current, nodes;

        // IE+11 - untested with other browsers.
        if (!document.currentScript && typeof MutationObserver=='function') {
            observer = new MutationObserver(function(mutations) {
                if (document.readyState=='complete') observer.disconnect();
                mutations.forEach(function(mutation) {
                    nodes = mutation.addedNodes;
                    if (nodes.length && nodes[0].nodeName=='SCRIPT') {
                        current = nodes[0];
                    }
                });
            });
            observer.observe(window.document, {childList: true, subtree: true});
        }

        // PUBLIC
        return function() {

            if (document.readyState=='complete') return;

            // CHROME+29, FIREFOX+4, OPERA+16
            if (document.currentScript) return document.currentScript;

            var i, s=document.getElementsByTagName('SCRIPT');

            // MSIE+5-10
            if (s[0].readyState) 
                for(i=0; i<s.length; i++)
                    if (s[i].readyState=='interactive') return s[i];

            // IE+11
            if (current) return current;

            // BEST GUESS
            return s[s.length-1];

        }

    })()

这篇关于`document.write`是否适合查找与当前正在运行的脚本相关联的元素?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆