最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

Load jQuery with JavaScript using Promises - Stack Overflow

programmeradmin0浏览0评论

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:

// Anonymous "self-invoking" function
(function() {
    // Load the script
    var script = document.createElement("SCRIPT");
    script.src = '.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?

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 = '.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.)

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:

// 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?

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.)

Share Improve this question edited May 23, 2017 at 12:26 CommunityBot 11 silver badge asked Jan 6, 2016 at 16:42 rydashrydash 3013 silver badges12 bronze badges 1
  • You would have to continue using your old code, and only resolve the promise when jquery is ready. There's no need to reject it in this case, unless jquery fails to load after a period of time. – Kevin B Commented Jan 6, 2016 at 16:49
Add a comment  | 

4 Answers 4

Reset to default 14

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:

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.

  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.

When you have multiple scripts with dependencies, I've found a promise sequence like this works best:

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

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.

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

For example (before setting 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.

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.

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");
      }
    });
});
发布评论

评论列表(0)

  1. 暂无评论