diff --git a/lib/promises-aplus/promises-aplus-test-adapter.js b/lib/promises-aplus/promises-aplus-test-adapter.js index bcd16da7e70b..fdc243d72fa6 100644 --- a/lib/promises-aplus/promises-aplus-test-adapter.js +++ b/lib/promises-aplus/promises-aplus-test-adapter.js @@ -9,21 +9,21 @@ minErr, extend */ -/* eslint-disable no-unused-vars */ -var isFunction = function isFunction(value) {return typeof value === 'function';}; -var isPromiseLike = function isPromiseLike(obj) {return obj && isFunction(obj.then);}; -var isObject = function isObject(value) {return value != null && typeof value === 'object';}; -var isUndefined = function isUndefined(value) {return typeof value === 'undefined';}; +/* eslint-disable no-unused-vars */ +function isFunction(value) { return typeof value === 'function'; } +function isPromiseLike(obj) { return obj && isFunction(obj.then); } +function isObject(value) { return value !== null && typeof value === 'object'; } +function isUndefined(value) { return typeof value === 'undefined'; } -var minErr = function minErr(module, constructor) { +function minErr(module, constructor) { return function() { var ErrorConstructor = constructor || Error; throw new ErrorConstructor(module + arguments[0] + arguments[1]); }; -}; +} -var extend = function extend(dst) { +function extend(dst) { for (var i = 1, ii = arguments.length; i < ii; i++) { var obj = arguments[i]; if (obj) { @@ -35,18 +35,11 @@ var extend = function extend(dst) { } } return dst; -}; +} +/* eslint-enable */ var $q = qFactory(process.nextTick, function noopExceptionHandler() {}); exports.resolved = $q.resolve; exports.rejected = $q.reject; -exports.deferred = function() { - var deferred = $q.defer(); - - return { - promise: deferred.promise, - resolve: deferred.resolve, - reject: deferred.reject - }; -}; +exports.deferred = $q.defer; diff --git a/src/ng/compile.js b/src/ng/compile.js index df611d315c3d..d264d6689684 100644 --- a/src/ng/compile.js +++ b/src/ng/compile.js @@ -3131,6 +3131,10 @@ function $CompileProvider($provide, $$sanitizeUriProvider) { childBoundTranscludeFn); } linkQueue = null; + }).catch(function(error) { + if (error instanceof Error) { + $exceptionHandler(error); + } }).catch(noop); return function delayedNodeLinkFn(ignoreChildLinkFn, scope, node, rootElement, boundTranscludeFn) { diff --git a/src/ng/q.js b/src/ng/q.js index 7b9de29b0d52..b4568c607427 100644 --- a/src/ng/q.js +++ b/src/ng/q.js @@ -9,8 +9,8 @@ * A service that helps you run functions asynchronously, and use their return values (or exceptions) * when they are done processing. * - * This is an implementation of promises/deferred objects inspired by - * [Kris Kowal's Q](https://github.com/kriskowal/q). + * This is a [Promises/A+](https://promisesaplus.com/)-compliant implementation of promises/deferred + * objects inspired by [Kris Kowal's Q](https://github.com/kriskowal/q). * * $q can be used in two fashions --- one which is more similar to Kris Kowal's Q or jQuery's Deferred * implementations, and the other which resembles ES6 (ES2015) promises to some degree. @@ -366,7 +366,6 @@ function qFactory(nextTick, exceptionHandler, errorOnUnhandledRejections) { } } catch (e) { deferred.reject(e); - exceptionHandler(e); } } } finally { @@ -417,7 +416,6 @@ function qFactory(nextTick, exceptionHandler, errorOnUnhandledRejections) { } else { this.$$resolve(val); } - }, $$resolve: function(val) { @@ -425,7 +423,7 @@ function qFactory(nextTick, exceptionHandler, errorOnUnhandledRejections) { var that = this; var done = false; try { - if ((isObject(val) || isFunction(val))) then = val && val.then; + if (isObject(val) || isFunction(val)) then = val.then; if (isFunction(then)) { this.promise.$$state.status = -1; then.call(val, resolvePromise, rejectPromise, simpleBind(this, this.notify)); @@ -436,7 +434,6 @@ function qFactory(nextTick, exceptionHandler, errorOnUnhandledRejections) { } } catch (e) { rejectPromise(e); - exceptionHandler(e); } function resolvePromise(val) { diff --git a/src/ng/templateRequest.js b/src/ng/templateRequest.js index e7c1007beddc..1046f0223a92 100644 --- a/src/ng/templateRequest.js +++ b/src/ng/templateRequest.js @@ -60,53 +60,59 @@ function $TemplateRequestProvider() { * * @property {number} totalPendingRequests total amount of pending template requests being downloaded. */ - this.$get = ['$templateCache', '$http', '$q', '$sce', function($templateCache, $http, $q, $sce) { + this.$get = ['$exceptionHandler', '$templateCache', '$http', '$q', '$sce', + function($exceptionHandler, $templateCache, $http, $q, $sce) { - function handleRequestFn(tpl, ignoreRequestError) { - handleRequestFn.totalPendingRequests++; + function handleRequestFn(tpl, ignoreRequestError) { + handleRequestFn.totalPendingRequests++; - // We consider the template cache holds only trusted templates, so - // there's no need to go through whitelisting again for keys that already - // are included in there. This also makes Angular accept any script - // directive, no matter its name. However, we still need to unwrap trusted - // types. - if (!isString(tpl) || isUndefined($templateCache.get(tpl))) { - tpl = $sce.getTrustedResourceUrl(tpl); - } + // We consider the template cache holds only trusted templates, so + // there's no need to go through whitelisting again for keys that already + // are included in there. This also makes Angular accept any script + // directive, no matter its name. However, we still need to unwrap trusted + // types. + if (!isString(tpl) || isUndefined($templateCache.get(tpl))) { + tpl = $sce.getTrustedResourceUrl(tpl); + } - var transformResponse = $http.defaults && $http.defaults.transformResponse; + var transformResponse = $http.defaults && $http.defaults.transformResponse; - if (isArray(transformResponse)) { - transformResponse = transformResponse.filter(function(transformer) { - return transformer !== defaultHttpResponseTransform; - }); - } else if (transformResponse === defaultHttpResponseTransform) { - transformResponse = null; - } + if (isArray(transformResponse)) { + transformResponse = transformResponse.filter(function(transformer) { + return transformer !== defaultHttpResponseTransform; + }); + } else if (transformResponse === defaultHttpResponseTransform) { + transformResponse = null; + } - return $http.get(tpl, extend({ - cache: $templateCache, - transformResponse: transformResponse - }, httpOptions)) - .finally(function() { - handleRequestFn.totalPendingRequests--; - }) - .then(function(response) { - $templateCache.put(tpl, response.data); - return response.data; - }, handleError); + return $http.get(tpl, extend({ + cache: $templateCache, + transformResponse: transformResponse + }, httpOptions)) + .finally(function() { + handleRequestFn.totalPendingRequests--; + }) + .then(function(response) { + $templateCache.put(tpl, response.data); + return response.data; + }, handleError); - function handleError(resp) { - if (!ignoreRequestError) { - throw $templateRequestMinErr('tpload', 'Failed to load template: {0} (HTTP status: {1} {2})', - tpl, resp.status, resp.statusText); + function handleError(resp) { + if (!ignoreRequestError) { + resp = $templateRequestMinErr('tpload', + 'Failed to load template: {0} (HTTP status: {1} {2})', + tpl, resp.status, resp.statusText); + + $exceptionHandler(resp); + } + + return $q.reject(resp); } - return $q.reject(resp); } - } - handleRequestFn.totalPendingRequests = 0; + handleRequestFn.totalPendingRequests = 0; - return handleRequestFn; - }]; + return handleRequestFn; + } + ]; } diff --git a/test/ng/compileSpec.js b/test/ng/compileSpec.js index 492741a4496a..ef26f747f1e5 100755 --- a/test/ng/compileSpec.js +++ b/test/ng/compileSpec.js @@ -1854,17 +1854,18 @@ describe('$compile', function() { )); - it('should throw an error and clear element content if the template fails to load', inject( - function($compile, $httpBackend, $rootScope) { - $httpBackend.expect('GET', 'hello.html').respond(404, 'Not Found!'); - element = $compile('
template.html
'); - expect(function() { - $compile('