Javascript 动态脚本加载同步

Javascript 动态脚本加载同步,javascript,Javascript,我有一个脚本,它知道如何动态加载包含javascript类的脚本。 我正在使用以下代码加载类脚本: var head = document.getElementsByTagName("head")[0]; var script = document.createElement("script"); script.type = "text/javascript"; script.src = "myscript.js"; head.appendChild(script); 然后,我尝试使用eval

我有一个脚本,它知道如何动态加载包含javascript类的脚本。 我正在使用以下代码加载类脚本:

var head = document.getElementsByTagName("head")[0];
var script = document.createElement("script");
script.type = "text/javascript";
script.src = "myscript.js";
head.appendChild(script);
然后,我尝试使用eval创建新类:

var classObj = eval(" new MyClass()" );
问题是eval的代码正在bofre执行,脚本已加载到内存中,我得到一个错误,即
MyClass未定义。


有没有办法同步这些事件?我需要确保脚本已完全加载到内存中,然后才能开始从中分配类。

您确定向DOM添加
元素会导致浏览器实际评估脚本吗?我有一个模糊的记忆,在某个地方读到它没有,但也许我昨天吸入了太多的烤箱清洁剂。

阿米尔,在我看来,脚本似乎仍然在服务器上,也就是说,没有被浏览器加载。所以你的
head.appendChild(脚本)正在追加null。您不能仅通过说出脚本名称就从服务器获取脚本,您需要使用ajax请求脚本并将其注入页面,或者使用
标记将其加载到页面中。

使用(JavaScript库)
函数异步加载脚本。使用回调函数创建对象。例如:

$.getScript("script.js", function () { var classObj = new MyClass(); });
$.getScript(“script.js”,函数(){ var classObj=新的MyClass(); });
在符合Web标准的浏览器中,您需要将事件处理程序附加到onload方法或onreadystatechange,以检查Internet Explorer中的script.readyState属性是否等于“loaded”或“complete”

在收到已加载脚本的通知之前,您可能正在尝试访问尚未声明或创建的对象、函数和属性

以下是从my中的模块中提取的示例函数:

为了使其适应您的需要,您可以替换对catchError的调用,该调用将侦听器包装为捕获和记录错误,并使用修改后的函数:

var appendScript = function(parent, scriptElt, listener) {
    // append a script element as last child in parent and configure 
    // provided listener function for the script load event
    //
    // params:
    //   parent - (DOM element) (!nil) the parent node to append the script to
    //   scriptElt - (DOM element) (!nil) a new script element 
    //   listener - (function) (!nil) listener function for script load event
    //
    // Notes:
    //   - in IE, the load event is simulated by setting an intermediate 
    //     listener to onreadystate which filters events and fires the
    //     callback just once when the state is "loaded" or "complete"
    //
    //   - Opera supports both readyState and onload, but does not behave in
    //     the exact same way as IE for readyState, e.g. "loaded" may be
    //     reached before the script runs.

    var safelistener = function(){
      try {
        listener();
      } catch(e) {
        // do something with the error
      }
    };

    // Opera has readyState too, but does not behave in a consistent way
    if (scriptElt.readyState && scriptElt.onload!==null) {
      // IE only (onload===undefined) not Opera (onload===null)
      scriptElt.onreadystatechange = function() {
        if ( scriptElt.readyState === "loaded" || 
             scriptElt.readyState === "complete" ) {
          // Avoid memory leaks (and duplicate call to callback) in IE
          scriptElt.onreadystatechange = null;
          safelistener();
        }
      };
    } else {
      // other browsers (DOM Level 0)
      scriptElt.onload = safelistener;
    }
    parent.appendChild( scriptElt );
};
function load_complete() {
    var classObj = eval(" new MyClass()" );
}

既然您似乎能够编辑外部脚本(因为您使用警报对其进行了测试),为什么不将此代码放在该脚本中呢

如果您不能做到这一点(可能会生成额外的代码或共享第一个文件),只需在正在加载的脚本末尾添加一个函数调用,如下所示:

load_complete();
<script>
var head = document.getElementsByTagName("head")[0];
var script = document.createElement("script");
script.type = "text/javascript";
script.src = "myscript.js";
head.appendChild(script);

//this is in the same script block so it wouldn't work
//var classObj = eval(" new MyClass()" );
</script>

<script>
//this is in a separate script block so it will work
var classObj = eval(" new MyClass()" );
</script>
然后将额外代码放入该函数中:

var appendScript = function(parent, scriptElt, listener) {
    // append a script element as last child in parent and configure 
    // provided listener function for the script load event
    //
    // params:
    //   parent - (DOM element) (!nil) the parent node to append the script to
    //   scriptElt - (DOM element) (!nil) a new script element 
    //   listener - (function) (!nil) listener function for script load event
    //
    // Notes:
    //   - in IE, the load event is simulated by setting an intermediate 
    //     listener to onreadystate which filters events and fires the
    //     callback just once when the state is "loaded" or "complete"
    //
    //   - Opera supports both readyState and onload, but does not behave in
    //     the exact same way as IE for readyState, e.g. "loaded" may be
    //     reached before the script runs.

    var safelistener = function(){
      try {
        listener();
      } catch(e) {
        // do something with the error
      }
    };

    // Opera has readyState too, but does not behave in a consistent way
    if (scriptElt.readyState && scriptElt.onload!==null) {
      // IE only (onload===undefined) not Opera (onload===null)
      scriptElt.onreadystatechange = function() {
        if ( scriptElt.readyState === "loaded" || 
             scriptElt.readyState === "complete" ) {
          // Avoid memory leaks (and duplicate call to callback) in IE
          scriptElt.onreadystatechange = null;
          safelistener();
        }
      };
    } else {
      // other browsers (DOM Level 0)
      scriptElt.onload = safelistener;
    }
    parent.appendChild( scriptElt );
};
function load_complete() {
    var classObj = eval(" new MyClass()" );
}

它比任何类型的加载触发器都简单、简单。此外,如果js文件是共享的,那么您可以在使用它的每个页面上使用不同的load_complete函数(只要确保始终定义load_complete,即使它是空的).

我认为这实际上可以通过确保将加载外部脚本的代码和使用外部脚本的代码放在单独的脚本块中来解决,如下所示:

load_complete();
<script>
var head = document.getElementsByTagName("head")[0];
var script = document.createElement("script");
script.type = "text/javascript";
script.src = "myscript.js";
head.appendChild(script);

//this is in the same script block so it wouldn't work
//var classObj = eval(" new MyClass()" );
</script>

<script>
//this is in a separate script block so it will work
var classObj = eval(" new MyClass()" );
</script>

var head=document.getElementsByTagName(“head”)[0];
var script=document.createElement(“脚本”);
script.type=“text/javascript”;
script.src=“myscript.js”;
head.appendChild(脚本);
//这在同一个脚本块中,因此无法工作
//var classObj=eval(“新MyClass()”);
//这是在一个单独的脚本块中,因此它可以工作
var classObj=eval(“新MyClass()”);

是。它被称为按需JavaScript。你可以在这里读到更多关于它的内容:一开始我是这么想的。我对它进行了调试,发现脚本在几毫秒后就可以使用了。我添加了一个警报(“我已加载”);它会立即附加脚本元素,但会异步加载和执行脚本代码,这就是该类无法立即使用的原因。根据
getScript()
文档,这是不可靠的:“加载脚本后会触发回调,但不一定要执行。”请检查以下相关答案: