diff --git a/angular-widget.js b/angular-widget.js index 807930fd..4e4a8e75 100644 --- a/angular-widget.js +++ b/angular-widget.js @@ -231,7 +231,7 @@ angular.module("angularWidgetInternal").directive("ngWidget", [ "$http", "$templ angular.module("angularWidgetInternal").value("headElement", document.getElementsByTagName("head")[0]).factory("requirejs", function() { return window.requirejs || null; }).value("navigator", navigator).factory("tagAppender", [ "$q", "$rootScope", "headElement", "$interval", "navigator", "$document", "requirejs", "$browser", function($q, $rootScope, headElement, $interval, navigator, $document, requirejs, $browser) { - var requireCache = []; + var requireCache = {}; var styleSheets = $document[0].styleSheets; function noprotocol(url) { return url.replace(/^.*:\/\//, "//"); @@ -252,10 +252,10 @@ angular.module("angularWidgetInternal").value("headElement", document.getElement }); return deferred.promise; } - if (requireCache.indexOf(url) !== -1) { - deferred.resolve(); - return deferred.promise; + if (url in requireCache) { + return requireCache[url]; } + requireCache[url] = deferred.promise; var fileref; if (filetype === "css") { fileref = angular.element("")[0]; @@ -271,6 +271,7 @@ angular.module("angularWidgetInternal").value("headElement", document.getElement headElement.appendChild(fileref); fileref.onerror = function() { fileref.onerror = fileref.onload = fileref.onreadystatechange = null; + delete requireCache[url]; if ($rootScope.$$phase) { deferred.reject(); } else { @@ -283,7 +284,6 @@ angular.module("angularWidgetInternal").value("headElement", document.getElement if (!done && (!this.readyState || this.readyState === "loaded" || this.readyState === "complete")) { done = true; fileref.onerror = fileref.onload = fileref.onreadystatechange = null; - requireCache.push(url); if ($rootScope.$$phase) { deferred.resolve(); } else { diff --git a/app/scripts/services/tag-appender.js b/app/scripts/services/tag-appender.js index 79b27e4d..050f3a57 100644 --- a/app/scripts/services/tag-appender.js +++ b/app/scripts/services/tag-appender.js @@ -8,7 +8,7 @@ angular.module('angularWidgetInternal') }) .value('navigator', navigator) .factory('tagAppender', function ($q, $rootScope, headElement, $interval, navigator, $document, requirejs, $browser) { - var requireCache = []; + var requireCache = {}; var styleSheets = $document[0].styleSheets; function noprotocol(url) { @@ -31,10 +31,10 @@ angular.module('angularWidgetInternal') }); return deferred.promise; } - if (requireCache.indexOf(url) !== -1) { - deferred.resolve(); - return deferred.promise; + if (url in requireCache) { + return requireCache[url]; } + requireCache[url] = deferred.promise; var fileref; if (filetype === 'css') { @@ -52,7 +52,7 @@ angular.module('angularWidgetInternal') headElement.appendChild(fileref); fileref.onerror = function () { fileref.onerror = fileref.onload = fileref.onreadystatechange = null; - + delete requireCache[url]; //the $$phase test is required due to $interval mock, should be removed when $interval is fixed if ($rootScope.$$phase) { deferred.reject(); @@ -66,7 +66,6 @@ angular.module('angularWidgetInternal') if (!done && (!this.readyState || this.readyState === 'loaded' || this.readyState === 'complete')) { done = true; fileref.onerror = fileref.onload = fileref.onreadystatechange = null; - requireCache.push(url); //the $$phase test is required due to $interval mock, should be removed when $interval is fixed if ($rootScope.$$phase) { diff --git a/test/spec/services/tag-appender.spec.js b/test/spec/services/tag-appender.spec.js index 86d19b37..31e15a66 100644 --- a/test/spec/services/tag-appender.spec.js +++ b/test/spec/services/tag-appender.spec.js @@ -73,6 +73,24 @@ describe('Unit testing tagAppender service', function () { .toBe(''); })); + it('should return the same promise when same file loads twice simultaneously ', inject (function (tagAppender) { + var firstLoadPromise = tagAppender('dummy.js', 'js'); + var secondLoadPromise = tagAppender('dummy.js', 'js'); + expect(firstLoadPromise).toEqual(secondLoadPromise); + })); + + it('should re try to download the file in case first attempt failed', inject (function (tagAppender) { + var secondAttemptSuccess = jasmine.createSpy('secondAttemptSuccess'); + + tagAppender('dummy.js', 'js').catch(function () { + tagAppender('dummy.js', 'js').then(secondAttemptSuccess); + simulateLoadSuccessOnCall(1); + }); + + simulateLoadErrorOnCall(0); + expect(secondAttemptSuccess).toHaveBeenCalled(); + })); + it('should append link tag when css file is added', inject(function (tagAppender) { tagAppender('dummy.css', 'css'); expect(headElement.appendChild.calls.length).toBe(1); @@ -198,4 +216,12 @@ describe('Unit testing tagAppender service', function () { expect(success.calls.length).toBe(1); })); + function simulateLoadSuccessOnCall(callIndex) { + headElement.appendChild.calls[callIndex].args[0].onload(); + } + + function simulateLoadErrorOnCall(callIndex) { + headElement.appendChild.calls[callIndex].args[0].onerror(); + } + });