使用承诺加载jQuery

时间:2022-08-10 01:20:14

A previous question revealed how to load in jQuery using native JavaScript. I've successfully used the callback code from the answer there, replicated here:

之前的一个问题揭示了如何使用本机JavaScript加载jQuery。我已经成功地使用了那里的答案的回调代码,复制到这里:

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

How can I accomplish the same thing using native JavaScript Promises?

如何使用本机JavaScript承诺完成相同的任务?

The reason I ask is because I suddenly need to chain off of the earlier callback, and it's a friggin' mess. I'm hoping Promises are a better way, and I have no real interest in using a loader framework.

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

Here's what I've got so far, but the Promise always ends up rejected:

这是我迄今为止所得到的,但承诺总是会被拒绝:

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

(I'm sorry in advance for my complete ignorance.)

(我很抱歉,因为我完全无知。)

3 个解决方案

#1


7  

Here's a version that makes a simple loadScript() function that returns a promise and then provides a wrapper around it that detects whether jQuery is already loaded:

下面是一个简单的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
});

Notes on your code:

笔记在你的代码:

  1. In your first code block, setting a single timer and assuming that the script will be loaded when that timer fires is like playing roulette. It might work most of the time, but it is not a purely reliable method of doing things. In addition, to be safe, you have to set the timer to a longer period of time than is usually necessary. Instead, you should trigger based on the onload callback of the script. Then you will know exactly when the script is ready with 100% reliability.

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

  2. In your second code block, your promise version successfully handles the case where jQuery is already loaded, but then rejects() when jQuery must be custom loaded. As you can see from my example, you need to resolve() when the newly loaded script tag has finished loading for your promise to work as desired.

    在您的第二个代码块中,您的承诺版本成功地处理了jQuery已经加载的情况,但是当jQuery必须自定义加载时,则拒绝()。正如您从我的示例中看到的,当新加载的脚本标记完成了您所希望的工作时,您需要解析()。

#2


0  

Scripts inserted into the page in this way are executed asynchronously. (See "Dynamically importing scripts" on MDN.) As a result, window.jQuery will always be undefined.

以这种方式插入到页面中的脚本将异步执行。(参见MDN上的“动态导入脚本”。)因此,窗口。jQuery总是没有定义。

Try attaching an onload handler to the script element such that resolution of the Promise is only performed once the script has been executed.

尝试将onload处理程序附加到脚本元素,这样,只有在执行脚本之后才执行承诺的解析。

For example (before setting script.src):

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

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

As usual, this method is not compatible with all browsers. Check this post out for ways to accommodate them.

与往常一样,该方法不兼容所有浏览器。查看这篇文章,寻找适合他们的方法。

#3


0  

The problem is that this is an asyncrhonous non-blocking way of loading javascript. You'll have to wait for the browser to download the script.

问题是,这是一种加载javascript的异步非阻塞方式。您将不得不等待浏览器下载脚本。

This is a possible solution:

这是一种可能的解决办法:

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

#1


7  

Here's a version that makes a simple loadScript() function that returns a promise and then provides a wrapper around it that detects whether jQuery is already loaded:

下面是一个简单的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
});

Notes on your code:

笔记在你的代码:

  1. In your first code block, setting a single timer and assuming that the script will be loaded when that timer fires is like playing roulette. It might work most of the time, but it is not a purely reliable method of doing things. In addition, to be safe, you have to set the timer to a longer period of time than is usually necessary. Instead, you should trigger based on the onload callback of the script. Then you will know exactly when the script is ready with 100% reliability.

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

  2. In your second code block, your promise version successfully handles the case where jQuery is already loaded, but then rejects() when jQuery must be custom loaded. As you can see from my example, you need to resolve() when the newly loaded script tag has finished loading for your promise to work as desired.

    在您的第二个代码块中,您的承诺版本成功地处理了jQuery已经加载的情况,但是当jQuery必须自定义加载时,则拒绝()。正如您从我的示例中看到的,当新加载的脚本标记完成了您所希望的工作时,您需要解析()。

#2


0  

Scripts inserted into the page in this way are executed asynchronously. (See "Dynamically importing scripts" on MDN.) As a result, window.jQuery will always be undefined.

以这种方式插入到页面中的脚本将异步执行。(参见MDN上的“动态导入脚本”。)因此,窗口。jQuery总是没有定义。

Try attaching an onload handler to the script element such that resolution of the Promise is only performed once the script has been executed.

尝试将onload处理程序附加到脚本元素,这样,只有在执行脚本之后才执行承诺的解析。

For example (before setting script.src):

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

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

As usual, this method is not compatible with all browsers. Check this post out for ways to accommodate them.

与往常一样,该方法不兼容所有浏览器。查看这篇文章,寻找适合他们的方法。

#3


0  

The problem is that this is an asyncrhonous non-blocking way of loading javascript. You'll have to wait for the browser to download the script.

问题是,这是一种加载javascript的异步非阻塞方式。您将不得不等待浏览器下载脚本。

This is a possible solution:

这是一种可能的解决办法:

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