如何在加载下一个javascript之前等待一个javascript被加载完成

3
我想知道如何等待一个脚本加载完成后再加载下一个。例如(并且完全加载另一个页面到页面中):
<html>
<script src = "script1"></script>

<script src = "script2"></script>

<script>
$(document).ready( function() {
    $("#content1").load("index2.html");
});
</script>
</html>

在成功加载并运行脚本1后,我想要加载脚本2,并在完全加载后将文档index2.html加载到此HTML文档中。

到目前为止,我尝试过以下方法,但它并不完全符合我的要求。

文件1:scriptOrderTest.html

<html>

<div id ="content1"></div>

<script src="js/jquery-3.2.1.min.js"></script>
<script>
var variable1 = undefined;
$(document).ready( function() {
    $.ajax({
      url: "script1.js",
      dataType: "script",
      success: () => {
        $.ajax({
          url: "script2.js",
          dataType: "script",
          success: () =>{
            // do the stuff you need
            $("#content1").load("index2.html");
          }
         });
       }
       });       
});
</script>
</html>

文件2:script1.js
console.log("Starting script 1");
function revealTime(){
    console.log("Oh, I just wasted 5 seconds of my life")   
}

//This script is just wasting time
setTimeout(revealTime,5000);

File3: script2.js

console.log("Starting script 2");
function revealTime(){
    console.log("Oh, I just wasted 5 seconds of my life AGAIN") ;
    variable1 = "Pizza";
}

//This script is just wasting time
setTimeout(revealTime,5000);

文件4:index2.html

<html>
<script src="js/jquery-3.2.1.min.js"></script>

<script>
    document.write("The variable is:"+variable1);   
</script>
</html>

首先,我们的目标是等待脚本执行完毕,这样变量才能在页面上输出值。但以上代码并不满足这一条件。

以上的代码就是做这件事情的。你遇到了什么问题? - T.J. Crowder
2个回答

2

您可以使用Promise并将操作链接在一起来解决此问题。

如果您创建一个添加脚本并告诉您何时完成的函数。

像这样:

function addScript(url){
  return new Promise((resolve, reject) => {
    console.log("Download", url);
    var script = document.createElement("script")
    script.type = "text/javascript";
    script.onload = function(){
      console.log(`Download done (${url})`);
      resolve(1);
    };

    script.src = url;
    document.getElementsByTagName("head")[0].appendChild(script);
  });
}

定义所有需要的脚本,我只是用vue举了一个无用的例子。

const scripts = [
  "https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.js",
  "https://cdnjs.cloudflare.com/ajax/libs/vue-router/3.0.1/vue-router.js"
];

顺序执行

在您提出的问题中,需要按顺序下载脚本文件,只有当第一个脚本文件下载完成后才能延迟下载下一个脚本文件。

const tasks = scripts[Symbol.iterator]();

function addAllScripts(callback){
  const url = tasks.next().value;
  if(url){
    addScript(url).then( () => { addAllScripts(callback); } );
  }else{
    callback();
  }
};
addAllScripts(() => {
  console.log("Ready");
  new Vue({
    el: '#app',
    template: '<p>hello world</p>'
  });
});

function addScript(url){
 return new Promise((resolve, reject) => {
   console.log("Download", url);
   var script = document.createElement("script")
    script.type = "text/javascript";
    script.onload = function(){
     console.log(`Download done (${url})`);
      resolve(1);
    };

    script.src = url;
    document.getElementsByTagName("head")[0].appendChild(script);
  });
}

const scripts = [
"https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.js",
"https://cdnjs.cloudflare.com/ajax/libs/vue-router/3.0.1/vue-router.js"
];

const tasks = scripts[Symbol.iterator]();

function addAllScripts(callback){
   const url = tasks.next().value;
    if(url){
      addScript(url).then( () => { addAllScripts(callback); } );
    }else{
      callback();
    }
};
addAllScripts(() => {
 console.log("Ready");
          new Vue({
            el: '#app',
            template: '<p>hello world</p>'
          });
});
<div id="app"></div>

并行执行

最佳解决方案,更快的执行速度——一次性添加所有脚本,等待所有脚本都完成。

const tasks = scripts.map(addScript);

Promise.all( tasks )
       .then(function(){
          console.log("Ready");
          new Vue({
            el: '#app',
            template: '<p>hello world</p>'
          });
       }); 

function addScript(url){
 return new Promise((resolve, reject) => {
   console.log("Download", url);
   var script = document.createElement("script")
    script.type = "text/javascript";
    script.onload = function(){
     console.log(`Download done (${url})`);
      resolve(1);
    };

    script.src = url;
    document.getElementsByTagName("head")[0].appendChild(script);
  });
}

const scripts = [
"https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.js",
"https://cdnjs.cloudflare.com/ajax/libs/vue-router/3.0.1/vue-router.js"
];

const tasks = scripts.map(addScript);

Promise.all( tasks )
       .then(function(){
          console.log("Ready");
          new Vue({
            el: '#app',
            template: '<p>hello world</p>'
          });
    }); 
<div id="app"></div>


你写的代码非常好,只是我不理解。也许我作为一名Java开发人员还不够有经验... - Kanerva Peter
1
JavaScript* ;) - 你不明白的部分是什么,我可以尝试澄清一下。 - keja
关于 SEQUENTIAL 解决方案代码片段的代码。也许您可以在每行上写一些注释,说明正在发生什么。我也不确定代码执行的流程,它从哪里开始,以及如何结束等等。 - Kanerva Peter
我的意思是,你使用的类似 promise 和 callback 以及 Vue() 对象,我一点都不知道。所有这些东西我还不会正确地使用 :p - Kanerva Peter
啊,好的,你不需要Vue相关的东西,只是因为我加载的脚本是Vue,所以才用它来演示脚本。但你可以在这里看到一些注释:https://jsfiddle.net/Lke59208/10/ - keja
显示剩余2条评论

1
将这个放在 document.ready 中:
$.ajax({
  url: url1,
  dataType: "script",
  success: () => {
     $.ajax({
       url: url2,
       dataType: "script",
       success: () =>{
         // do the stuff you need
       }
   });
  }
  });

我在评论中添加了一些信息,你可以检查一下我是否正确理解了你的意思吗? - Kanerva Peter
它并不完全按照我的意愿工作,首先,脚本2在被加载到页面之前并没有等待脚本1完成其任务。我想我会将代码粘贴到我的文件中以展示我所做的。 - Kanerva Peter
如果您使用了setTimeout,那么是的,在5秒内script1的setTimeout函数被调用之前,第二个脚本就开始加载了。 - Oleksandr Poshtaruk
因为问题在于,我无法控制脚本1中发生的事情。那是别人的工作,我无法更改。但我不想在他的脚本正确执行所有内容之前加载我的东西。 - Kanerva Peter
在这种情况下,如果您无法更改script1,则需要等待所有setTimeout操作完成。没有其他办法。 - Oleksandr Poshtaruk

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接