From bdfab0fcb4d20aea5a725571b2a6271015ab9277 Mon Sep 17 00:00:00 2001 From: Doug Moscrop Date: Mon, 19 Jan 2015 12:17:46 -0500 Subject: [PATCH] Only load items once (reuse promise) --- angular-load.js | 64 +++++++++++++++++++++++------------------ angular-load.min.js | 2 +- angular-load.min.js.map | 2 +- package.json | 3 +- tests.js | 12 ++++++++ 5 files changed, 52 insertions(+), 31 deletions(-) diff --git a/angular-load.js b/angular-load.js index 8f6436d..8f3ab84 100644 --- a/angular-load.js +++ b/angular-load.js @@ -6,52 +6,60 @@ angular.module('angularLoad', []) .service('angularLoad', ['$document', '$q', '$timeout', function ($document, $q, $timeout) { + function loader(createElement) { + var promises = {}; + + return function(url) { + if (typeof promises[url] === 'undefined') { + var deferred = $q.defer(); + var element = createElement(url); + + element.onload = element.onreadystatechange = function (e) { + $timeout(function () { + deferred.resolve(e); + }); + }; + element.onerror = function (e) { + $timeout(function () { + deferred.reject(e); + }); + }; + + promises[url] = deferred.promise; + } + + return promises[url]; + }; + } + /** * Dynamically loads the given script * @param src The url of the script to load dynamically * @returns {*} Promise that will be resolved once the script has been loaded. */ - this.loadScript = function (src) { - var deferred = $q.defer(); + this.loadScript = loader(function (src) { var script = $document[0].createElement('script'); - script.onload = script.onreadystatechange = function (e) { - $timeout(function () { - deferred.resolve(e); - }); - }; - script.onerror = function (e) { - $timeout(function () { - deferred.reject(e); - }); - }; + script.src = src; + $document[0].body.appendChild(script); - return deferred.promise; - }; + return script; + }); /** * Dynamically loads the given CSS file * @param href The url of the CSS to load dynamically * @returns {*} Promise that will be resolved once the CSS file has been loaded. */ - this.loadCSS = function (href) { - var deferred = $q.defer(); + this.loadCSS = loader(function (href) { var style = $document[0].createElement('link'); + style.rel = 'stylesheet'; style.type = 'text/css'; style.href = href; - style.onload = style.onreadystatechange = function (e) { - $timeout(function () { - deferred.resolve(e); - }); - }; - style.onerror = function (e) { - $timeout(function () { - deferred.reject(e); - }); - }; + $document[0].head.appendChild(style); - return deferred.promise; - }; + return style; + }); }]); })(); diff --git a/angular-load.min.js b/angular-load.min.js index 9241dab..38dbd89 100644 --- a/angular-load.min.js +++ b/angular-load.min.js @@ -1,2 +1,2 @@ -!function(){"use strict";angular.module("angularLoad",[]).service("angularLoad",["$document","$q","$timeout",function(a,b,c){this.loadScript=function(d){var e=b.defer(),f=a[0].createElement("script");return f.onload=f.onreadystatechange=function(a){c(function(){e.resolve(a)})},f.onerror=function(a){c(function(){e.reject(a)})},f.src=d,a[0].body.appendChild(f),e.promise},this.loadCSS=function(d){var e=b.defer(),f=a[0].createElement("link");return f.rel="stylesheet",f.type="text/css",f.href=d,f.onload=f.onreadystatechange=function(a){c(function(){e.resolve(a)})},f.onerror=function(a){c(function(){e.reject(a)})},a[0].head.appendChild(f),e.promise}}])}(); +!function(){"use strict";angular.module("angularLoad",[]).service("angularLoad",["$document","$q","$timeout",function(a,b,c){function d(a){var d={};return function(e){if("undefined"==typeof d[e]){var f=b.defer(),g=a(e);g.onload=g.onreadystatechange=function(a){c(function(){f.resolve(a)})},g.onerror=function(a){c(function(){f.reject(a)})},d[e]=f.promise}return d[e]}}this.loadScript=d(function(b){var c=a[0].createElement("script");return c.src=b,a[0].body.appendChild(c),c}),this.loadCSS=d(function(b){var c=a[0].createElement("link");return c.rel="stylesheet",c.type="text/css",c.href=b,a[0].head.appendChild(c),c})}])}(); //# sourceMappingURL=angular-load.min.js.map \ No newline at end of file diff --git a/angular-load.min.js.map b/angular-load.min.js.map index dc344ab..6ad8e91 100644 --- a/angular-load.min.js.map +++ b/angular-load.min.js.map @@ -1 +1 @@ -{"version":3,"file":"angular-load.min.js","sources":["angular-load.js"],"names":["angular","module","service","$document","$q","$timeout","this","loadScript","src","deferred","defer","script","createElement","onload","onreadystatechange","e","resolve","onerror","reject","body","appendChild","promise","loadCSS","href","style","rel","type","head"],"mappings":"CAEA,WACC,YAEAA,SAAQC,OAAO,kBACbC,QAAQ,eAAgB,YAAa,KAAM,WAAY,SAAUC,EAAWC,EAAIC,GAOhFC,KAAKC,WAAa,SAAUC,GAC3B,GAAIC,GAAWL,EAAGM,QACdC,EAASR,EAAU,GAAGS,cAAc,SAaxC,OAZAD,GAAOE,OAASF,EAAOG,mBAAqB,SAAUC,GACrDV,EAAS,WACRI,EAASO,QAAQD,MAGnBJ,EAAOM,QAAU,SAAUF,GAC1BV,EAAS,WACRI,EAASS,OAAOH,MAGlBJ,EAAOH,IAAMA,EACbL,EAAU,GAAGgB,KAAKC,YAAYT,GACvBF,EAASY,SAQjBf,KAAKgB,QAAU,SAAUC,GACxB,GAAId,GAAWL,EAAGM,QACdc,EAAQrB,EAAU,GAAGS,cAAc,OAevC,OAdAY,GAAMC,IAAM,aACZD,EAAME,KAAO,WACbF,EAAMD,KAAOA,EACbC,EAAMX,OAASW,EAAMV,mBAAqB,SAAUC,GACnDV,EAAS,WACRI,EAASO,QAAQD,MAGnBS,EAAMP,QAAU,SAAUF,GACzBV,EAAS,WACRI,EAASS,OAAOH,MAGlBZ,EAAU,GAAGwB,KAAKP,YAAYI,GACvBf,EAASY"} \ No newline at end of file +{"version":3,"file":"angular-load.min.js","sources":["angular-load.js"],"names":["angular","module","service","$document","$q","$timeout","loader","createElement","promises","url","deferred","defer","element","onload","onreadystatechange","e","resolve","onerror","reject","promise","this","loadScript","src","script","body","appendChild","loadCSS","href","style","rel","type","head"],"mappings":"CAEA,WACC,YAEAA,SAAQC,OAAO,kBACbC,QAAQ,eAAgB,YAAa,KAAM,WAAY,SAAUC,EAAWC,EAAIC,GAEhF,QAASC,GAAOC,GACf,GAAIC,KAEJ,OAAO,UAASC,GACf,GAA6B,mBAAlBD,GAASC,GAAsB,CACzC,GAAIC,GAAWN,EAAGO,QACdC,EAAUL,EAAcE,EAE5BG,GAAQC,OAASD,EAAQE,mBAAqB,SAAUC,GACvDV,EAAS,WACRK,EAASM,QAAQD,MAGnBH,EAAQK,QAAU,SAAUF,GAC3BV,EAAS,WACRK,EAASQ,OAAOH,MAIlBP,EAASC,GAAOC,EAASS,QAG1B,MAAOX,GAASC,IASlBW,KAAKC,WAAaf,EAAO,SAAUgB,GAClC,GAAIC,GAASpB,EAAU,GAAGI,cAAc,SAKxC,OAHAgB,GAAOD,IAAMA,EAEbnB,EAAU,GAAGqB,KAAKC,YAAYF,GACvBA,IAQRH,KAAKM,QAAUpB,EAAO,SAAUqB,GAC/B,GAAIC,GAAQzB,EAAU,GAAGI,cAAc,OAOvC,OALAqB,GAAMC,IAAM,aACZD,EAAME,KAAO,WACbF,EAAMD,KAAOA,EAEbxB,EAAU,GAAG4B,KAAKN,YAAYG,GACvBA"} \ No newline at end of file diff --git a/package.json b/package.json index e7dbd1d..e670f88 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "node": ">=0.10.0" }, "scripts": { - "test": "grunt test" + "test": "grunt test", + "build": "grunt build" } } diff --git a/tests.js b/tests.js index 8b60cf2..053a49a 100644 --- a/tests.js +++ b/tests.js @@ -60,6 +60,12 @@ describe('service angularLoad', function () { $timeout.flush(); expect(rejected).toBeTruthy(); }); + + it('should only append the script tag once', function() { + angularLoad.loadScript('https://www.test.org/somescript.js'); + angularLoad.loadScript('https://www.test.org/somescript.js'); + expect(mockDocument.body.appendChild.calls.all().length).toBe(1); + }); }); describe('#loadCSS', function() { @@ -97,5 +103,11 @@ describe('service angularLoad', function () { $timeout.flush(); expect(rejected).toBeTruthy(); }); + + it('should only append the stylesheet link once', function() { + angularLoad.loadCSS('https://www.test.org/styles.css'); + angularLoad.loadCSS('https://www.test.org/styles.css'); + expect(mockDocument.head.appendChild.calls.all().length).toBe(1); + }); }); });