Cargue jQuery con JavaScript utilizando Promises

Una pregunta anterior reveló cómo cargar en jQuery usando JavaScript nativo. He utilizado con éxito el código de callback de la respuesta allí, replicado aquí:

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

¿Cómo puedo lograr lo mismo usando Promises JavaScript nativos?

La razón por la que pregunto es porque de repente necesito desconectarme de la callback anterior, y es un desastre. Espero que las Protables sean una mejor manera, y no tengo ningún interés real en usar un marco de cargador.

Esto es lo que tengo hasta ahora, pero la Protable siempre termina rechazada:

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

(Lo siento de antemano por mi completa ignorancia).

Aquí hay una versión que hace que una function loadScript() simple devuelva una promise y luego proporciona un contenedor que detecta si jQuery ya está cargado:

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

Notas sobre tu código:

  1. En su primer bloque de código, configurar un solo timer y asumir que el script se cargará cuando ese timer se active es como jugar a la ruleta. Puede funcionar la mayor parte del time, pero no es un método puramente confiable de hacer las cosas. Además, para estar seguro, tiene que configurar el timer por un período de time más largo de lo que normalmente es necesario. En su lugar, debe desencadenar en function de la callback de la secuencia de commands de la secuencia de commands. Entonces sabrá exactamente cuándo está listo el script con 100% de confiabilidad.

  2. En su segundo bloque de código, su versión prometedora maneja con éxito el caso donde jQuery ya está cargado, pero luego rejects() cuando jQuery debe cargarse de manera personalizada. Como puede ver en mi ejemplo, necesita resolve() cuando la label del script recién cargado haya terminado de cargarse para que su promise funcione como lo desee.

Los scripts insertados en la página de esta manera se ejecutan de forma asíncrona. (Consulte "Importación dinámica de scripts" en MDN.) Como resultado, window.jQuery siempre estará undefined .

Intente asociar un controller de onload al elemento de secuencia de commands de modo que la resolución de la promise solo se realice una vez que se haya ejecutado la secuencia de commands.

Por ejemplo (antes de establecer script.src ):

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

Como es habitual, este método no es compatible con todos los browseres. Consulte esta publicación para conocer las forms de acomodarlos.

El problema es que esta es una forma asíncrona de no bloquear la carga de JavaScript. Tendrás que esperar a que el browser descargue el script.

Esta es una posible solución:

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