【问题标题】:Load jQuery with JavaScript using Promises使用 Promises 使用 JavaScript 加载 jQuery
【发布时间】:2016-04-10 20:15:35
【问题描述】:

A previous question revealed how to load in jQuery using native JavaScript.我已经成功使用了那里答案中的回调代码,在这里复制:

// 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...
    });
})();

我怎样才能使用native JavaScript Promises?完成同样的事情

我问的原因是因为我突然需要取消之前的回调,这真是一团糟。我希望 Promises 是一种更好的方法,我对使用加载器框架没有真正的兴趣。

这是我到目前为止所得到的,但 Promise 总是以被拒绝:

// 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);
  });

(对于我的完全无知,我提前道歉。)

【问题讨论】:

  • 你必须继续使用你的旧代码,并且只有在 jquery 准备好时才解决这个承诺。这种情况下不需要拒绝,除非jquery在一段时间后加载失败。

标签: javascript jquery promise


【解决方案1】:

这里有一个版本,它创建了一个简单的 loadScript() 函数,该函数返回一个 promise,然后提供一个包装器来检测 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
});

代码注释:

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

  2. 在您的第二个代码块中,您的 Promise 版本成功处理了已经加载 jQuery 的情况,但是当必须自定义加载 jQuery 时 rejects()。从我的示例中可以看出,当新加载的脚本标签完成加载时,您需要 resolve() 才能让您的承诺按预期工作。

【讨论】:

  • 非常有用,特别是使用抽象的loadScript() 函数,以防我将来需要调用其他脚本!感谢您对现有代码的注释 - 我在这些领域的知识肯定存在鸿沟。
【解决方案2】:

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

let p1 = loadScript('https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js')
let p2 = loadScript('scripts/moment.min.js')
            
Promise.allSettled([p1, p2])
.then(function() {
    return loadScript('scripts/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)
  })
}

【讨论】:

    【解决方案3】:

    以这种方式插入页面的脚本是异步执行的。 (请参阅 MDN 上的 "Dynamically importing scripts"。)因此,window.jQuery 将始终为 undefined

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

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

    script.onload = function () {
        if (window.jQuery) {
            resolve("YAY");
        } else {
            reject("UGH");
        }
    };
    

    像往常一样,这种方法并不兼容所有浏览器。查看this post out 了解如何容纳它们。

    【讨论】:

      【解决方案4】:

      问题在于这是一种异步非阻塞加载 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");
            }
          });
      });
      

      【讨论】:

        猜你喜欢
        • 2012-04-24
        • 1970-01-01
        • 2018-04-29
        • 2011-07-21
        • 2013-02-25
        • 2015-04-28
        • 2014-12-30
        • 1970-01-01
        • 2013-11-12
        相关资源
        最近更新 更多