使用承诺用JavaScript加载jQuery

使用承诺用JavaScript加载jQuery,javascript,jquery,promise,Javascript,Jquery,Promise,我已成功使用了答案中的回调代码,在此处复制: // Anonymous "self-invoking" function (function() { // Load the script var script = document.createElement("SCRIPT"); script.src = 'https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js'; script.type

我已成功使用了答案中的回调代码,在此处复制:

// Anonymous "self-invoking" function
(function() {
    // Load the script
    var script = document.createElement("SCRIPT");
    script.src = 'https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js';
    script.type = 'text/javascript';
    document.getElementsByTagName("head")[0].appendChild(script);

    // Poll for jQuery to come into existance
    var checkReady = function(callback) {
        if (window.jQuery) {
            callback(jQuery);
        }
        else {
            window.setTimeout(function() { checkReady(callback); }, 100);
        }
    };

    // Start polling...
    checkReady(function($) {
        // Use $ here...
    });
})();
如何使用

我问这个问题的原因是因为我突然需要中断先前的回调,而这真是一团糟。我希望承诺是一种更好的方式,我对使用加载器框架没有真正的兴趣

到目前为止,我所得到的是,但承诺总是被拒绝:

// This code doesn't work quite right.
// Poll for jQuery to come into existance using a Promise
var jQueryReady = new Promise(
    function(resolve, reject) {

      // Load jQuery
      var script = document.createElement('SCRIPT');
      script.type = 'text/javascript';
      script.src = 'https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js';
      document.getElementsByTagName('head')[0].appendChild(script);

      if (window.jQuery) {
        resolve("YAY");
      } else {
        reject("UGH");
      }
    });

jQueryReady.then(
  function(success) {
    console.log(success);
  },
  function(error) {
    console.error("Really helpful error:", error);
  });

(很抱歉我完全不知道。)

以这种方式插入页面的脚本是异步执行的。因此,
window.jQuery
将始终是
未定义的

尝试将
onload
处理程序附加到脚本元素,以便仅在脚本执行后执行承诺的解析

例如(在设置
script.src
之前):


通常,此方法与所有浏览器都不兼容。检查适应它们的方法。

问题在于,这是一种异步非阻塞加载javascript的方法。您必须等待浏览器下载脚本

这是一个可能的解决方案:

var jQueryReady = new Promise(
  function(resolve, reject) {

    // Load jQuery
    var script = document.createElement('SCRIPT');
    script.type = 'text/javascript';
    script.src = 'https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js';
    document.getElementsByTagName('head')[0].appendChild(script);

    // You should also have a timeout in case your script never loads
    var timeoutHandler = setTimeout(10000, function() {
      if (checkIntervalHandler) clearInterval(checkIntervalHandler);
      reject("UGH");
    });

    var checkIntervalHandler = setInterval(500, function() {
      if (window.jQuery) {
        if(timeoutHandler) clearTimeout(timeoutHandler);
        resolve("YAY");
      }
    });
});

下面是一个版本,它生成了一个简单的
loadScript()
函数,该函数返回一个承诺,然后在其周围提供一个包装器,用于检测jQuery是否已加载:

function loadScript(url) {
    return new Promise(function(resolve, reject) {
        var script = document.createElement("script");
        script.onload = resolve;
        script.onerror = reject;
        script.src = url;
        document.getElementsByTagName("head")[0].appendChild(script);
    });
}

function loadjQuery() {
    if (window.jQuery) {
        // already loaded and ready to go
        return Promise.resolve();
    } else {
        return loadScript('https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js');
    }
}


// Usage:
loadjQuery().then(function() {
    // code here that uses jQuery
}, function() {
    // error loading jQuery
});
关于代码的注释:

  • 在您的第一个代码块中,设置一个计时器并假设该计时器启动时将加载脚本就像玩轮盘赌一样。它可能在大部分时间都有效,但它不是一种纯粹可靠的做事方法。此外,为了安全起见,您必须将计时器设置为比通常需要更长的时间。相反,您应该基于脚本的
    onload
    回调进行触发。然后,您将准确地知道脚本何时准备就绪,并且具有100%的可靠性

  • 在第二个代码块中,promise版本成功地处理了jQuery已经加载的情况,但是当jQuery必须自定义加载时,
    rejects()
    。正如您从我的示例中看到的,当新加载的脚本标记完成加载时,您需要
    resolve()
    ,才能保证按预期工作


  • 当您有多个具有依赖关系的脚本时,我发现这样的承诺序列最有效:

    let p1 = loadScript('https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js')
    let p2 = loadScript('//d3oax736nfit4h.cloudfront.net/fv/moment.min.js')
                
    Promise.allSettled([p1, p2])
    .then(function() {
        return loadScript('/myScript.js')
    }).then(function() {
        console.log('All Scripts Loaded!')
        initMyScript()
    })
    .catch(error => {
        console.error(error.message)
    })
    
    
    function loadScript(src) {
      return new Promise(function(resolve, reject) {
        let script = document.createElement('script')
        script.src = src
        script.onload = resolve
        script.onerror = reject
        document.head.append(script)
      })
    }
    

    您必须继续使用旧代码,并且只有在jquery就绪时才能解析承诺。在这种情况下,没有必要拒绝它,除非jquery在一段时间后无法加载。这非常有用,特别是使用抽象的
    loadScript()
    函数,以防将来需要使用其他脚本!感谢您对现有代码的注释-我在这些方面的知识肯定有差距。
    let p1 = loadScript('https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js')
    let p2 = loadScript('//d3oax736nfit4h.cloudfront.net/fv/moment.min.js')
                
    Promise.allSettled([p1, p2])
    .then(function() {
        return loadScript('/myScript.js')
    }).then(function() {
        console.log('All Scripts Loaded!')
        initMyScript()
    })
    .catch(error => {
        console.error(error.message)
    })
    
    
    function loadScript(src) {
      return new Promise(function(resolve, reject) {
        let script = document.createElement('script')
        script.src = src
        script.onload = resolve
        script.onerror = reject
        document.head.append(script)
      })
    }