diff options
| author | Misko Hevery | 2011-03-23 09:33:29 -0700 |
|---|---|---|
| committer | Vojta Jina | 2011-08-02 01:00:03 +0200 |
| commit | 8f0dcbab804180828d6859b1340c86cf161209fb (patch) | |
| tree | d13d47d47a1889cb7c96a87cecacd2e25307d51c /src/service | |
| parent | 1f4b417184ce53af15474de065400f8a686430c5 (diff) | |
| download | angular.js-8f0dcbab804180828d6859b1340c86cf161209fb.tar.bz2 | |
feat(scope): new and improved scope implementation
- Speed improvements (about 4x on flush phase)
- Memory improvements (uses no function closures)
- Break $eval into $apply, $dispatch, $flush
- Introduced $watch and $observe
Breaks angular.equals() use === instead of ==
Breaks angular.scope() does not take parent as first argument
Breaks scope.$watch() takes scope as first argument
Breaks scope.$set(), scope.$get are removed
Breaks scope.$config is removed
Breaks $route.onChange callback has not "this" bounded
Diffstat (limited to 'src/service')
| -rw-r--r-- | src/service/cookies.js | 4 | ||||
| -rw-r--r-- | src/service/defer.js | 11 | ||||
| -rw-r--r-- | src/service/invalidWidgets.js | 4 | ||||
| -rw-r--r-- | src/service/location.js | 47 | ||||
| -rw-r--r-- | src/service/route.js | 51 | ||||
| -rw-r--r-- | src/service/updateView.js | 6 | ||||
| -rw-r--r-- | src/service/xhr.bulk.js | 2 |
7 files changed, 54 insertions, 71 deletions
diff --git a/src/service/cookies.js b/src/service/cookies.js index d6be1364..74e63679 100644 --- a/src/service/cookies.js +++ b/src/service/cookies.js @@ -28,7 +28,7 @@ angularServiceInject('$cookies', function($browser) { lastBrowserCookies = currentCookies; copy(currentCookies, lastCookies); copy(currentCookies, cookies); - if (runEval) rootScope.$eval(); + if (runEval) rootScope.$apply(); } })(); @@ -37,7 +37,7 @@ angularServiceInject('$cookies', function($browser) { //at the end of each eval, push cookies //TODO: this should happen before the "delayed" watches fire, because if some cookies are not // strings or browser refuses to store some cookies, we update the model in the push fn. - this.$onEval(PRIORITY_LAST, push); + this.$observe(push); return cookies; diff --git a/src/service/defer.js b/src/service/defer.js index 551e8bc9..0a69912c 100644 --- a/src/service/defer.js +++ b/src/service/defer.js @@ -18,16 +18,11 @@ * @param {function()} fn A function, who's execution should be deferred. * @param {number=} [delay=0] of milliseconds to defer the function execution. */ -angularServiceInject('$defer', function($browser, $exceptionHandler, $updateView) { +angularServiceInject('$defer', function($browser) { + var scope = this; return function(fn, delay) { $browser.defer(function() { - try { - fn(); - } catch(e) { - $exceptionHandler(e); - } finally { - $updateView(); - } + scope.$apply(fn); }, delay); }; }, ['$browser', '$exceptionHandler', '$updateView']); diff --git a/src/service/invalidWidgets.js b/src/service/invalidWidgets.js index b7ef0b53..7c1b2a9f 100644 --- a/src/service/invalidWidgets.js +++ b/src/service/invalidWidgets.js @@ -42,7 +42,7 @@ angularServiceInject("$invalidWidgets", function(){ /* At the end of each eval removes all invalid widgets that are not part of the current DOM. */ - this.$onEval(PRIORITY_LAST, function() { + this.$watch(function() { for(var i = 0; i < invalidWidgets.length;) { var widget = invalidWidgets[i]; if (isOrphan(widget[0])) { @@ -56,7 +56,7 @@ angularServiceInject("$invalidWidgets", function(){ /** - * Traverses DOM element's (widget's) parents and considers the element to be an orphant if one of + * Traverses DOM element's (widget's) parents and considers the element to be an orphan if one of * it's parents isn't the current window.document. */ function isOrphan(widget) { diff --git a/src/service/location.js b/src/service/location.js index 1889266e..23531140 100644 --- a/src/service/location.js +++ b/src/service/location.js @@ -69,18 +69,14 @@ var URL_MATCH = /^(file|ftp|http|https):\/\/(\w+:{0,1}\w*@)?([\w\.-]*)(:([0-9]+) </doc:example> */ angularServiceInject("$location", function($browser) { - var scope = this, - location = {update:update, updateHash: updateHash}, - lastLocation = {}; + var location = {update: update, updateHash: updateHash}; + var lastLocation = {}; // last state since last update(). - $browser.onHashChange(function() { //register + $browser.onHashChange(bind(this, this.$apply, function() { //register update($browser.getUrl()); - copy(location, lastLocation); - scope.$eval(); - })(); //initialize + }))(); //initialize - this.$onEval(PRIORITY_FIRST, sync); - this.$onEval(PRIORITY_LAST, updateBrowser); + this.$watch(sync); return location; @@ -94,6 +90,8 @@ angularServiceInject("$location", function($browser) { * * @description * Updates the location object. + * Does not immediately update the browser + * Browser is updated at the end of $flush() * * Does not immediately update the browser. Instead the browser is updated at the end of $eval() * cycle. @@ -122,6 +120,8 @@ angularServiceInject("$location", function($browser) { location.href = composeHref(location); } + $browser.setUrl(location.href); + copy(location, lastLocation); } /** @@ -188,34 +188,21 @@ angularServiceInject("$location", function($browser) { if (!equals(location, lastLocation)) { if (location.href != lastLocation.href) { update(location.href); - return; - } - if (location.hash != lastLocation.hash) { - var hash = parseHash(location.hash); - updateHash(hash.hashPath, hash.hashSearch); } else { - location.hash = composeHash(location); - location.href = composeHref(location); + if (location.hash != lastLocation.hash) { + var hash = parseHash(location.hash); + updateHash(hash.hashPath, hash.hashSearch); + } else { + location.hash = composeHash(location); + location.href = composeHref(location); + } + update(location.href); } - update(location.href); } } /** - * If location has changed, update the browser - * This method is called at the end of $eval() phase - */ - function updateBrowser() { - sync(); - - if ($browser.getUrl() != location.href) { - $browser.setUrl(location.href); - copy(location, lastLocation); - } - } - - /** * Compose href string from a location object * * @param {Object} loc The location object with all properties diff --git a/src/service/route.js b/src/service/route.js index 9534968a..e1d0e7be 100644 --- a/src/service/route.js +++ b/src/service/route.js @@ -62,7 +62,7 @@ </doc:scenario> </doc:example> */ -angularServiceInject('$route', function(location, $updateView) { +angularServiceInject('$route', function($location, $updateView) { var routes = {}, onChange = [], matcher = switchRouteMatcher, @@ -207,66 +207,67 @@ angularServiceInject('$route', function(location, $updateView) { function updateRoute(){ - var childScope, routeParams, pathParams, segmentMatch, key, redir; + var selectedRoute, pathParams, segmentMatch, key, redir; + if ($route.current && $route.current.scope) { + $route.current.scope.$destroy(); + } $route.current = null; + // Match a route forEach(routes, function(rParams, rPath) { if (!pathParams) { - if (pathParams = matcher(location.hashPath, rPath)) { - routeParams = rParams; + if (pathParams = matcher($location.hashPath, rPath)) { + selectedRoute = rParams; } } }); - // "otherwise" fallback - routeParams = routeParams || routes[null]; + // No route matched; fallback to "otherwise" route + selectedRoute = selectedRoute || routes[null]; - if(routeParams) { - if (routeParams.redirectTo) { - if (isString(routeParams.redirectTo)) { + if(selectedRoute) { + if (selectedRoute.redirectTo) { + if (isString(selectedRoute.redirectTo)) { // interpolate the redirectTo string redir = {hashPath: '', - hashSearch: extend({}, location.hashSearch, pathParams)}; + hashSearch: extend({}, $location.hashSearch, pathParams)}; - forEach(routeParams.redirectTo.split(':'), function(segment, i) { + forEach(selectedRoute.redirectTo.split(':'), function(segment, i) { if (i==0) { redir.hashPath += segment; } else { segmentMatch = segment.match(/(\w+)(.*)/); key = segmentMatch[1]; - redir.hashPath += pathParams[key] || location.hashSearch[key]; + redir.hashPath += pathParams[key] || $location.hashSearch[key]; redir.hashPath += segmentMatch[2] || ''; delete redir.hashSearch[key]; } }); } else { // call custom redirectTo function - redir = {hash: routeParams.redirectTo(pathParams, location.hash, location.hashPath, - location.hashSearch)}; + redir = {hash: selectedRoute.redirectTo(pathParams, $location.hash, $location.hashPath, + $location.hashSearch)}; } - location.update(redir); - $updateView(); //TODO this is to work around the $location<=>$browser issues + $location.update(redir); return; } - childScope = createScope(parentScope); - $route.current = extend({}, routeParams, { - scope: childScope, - params: extend({}, location.hashSearch, pathParams) - }); + $route.current = extend({}, selectedRoute); + $route.current.params = extend({}, $location.hashSearch, pathParams); } //fire onChange callbacks - forEach(onChange, parentScope.$tryEval); + forEach(onChange, parentScope.$eval, parentScope); - if (childScope) { - childScope.$become($route.current.controller); + // Create the scope if we have mtched a route + if ($route.current) { + $route.current.scope = parentScope.$new($route.current.controller); } } - this.$watch(function(){return dirty + location.hash;}, updateRoute); + this.$watch(function(){return dirty + $location.hash;}, updateRoute)(); return $route; }, ['$location', '$updateView']); diff --git a/src/service/updateView.js b/src/service/updateView.js index 9ac7c1fb..b51e719b 100644 --- a/src/service/updateView.js +++ b/src/service/updateView.js @@ -35,8 +35,8 @@ * without angular knowledge and you may need to call '$updateView()' directly. * * Note: if you wish to update the view immediately (without delay), you can do so by calling - * {@link angular.scope.$eval} at any time from your code: - * <pre>scope.$root.$eval()</pre> + * {@link angular.scope.$apply} at any time from your code: + * <pre>scope.$apply()</pre> * * In unit-test mode the update is instantaneous and synchronous to simplify writing tests. * @@ -47,7 +47,7 @@ function serviceUpdateViewFactory($browser){ var scheduled; function update(){ scheduled = false; - rootScope.$eval(); + rootScope.$flush(); } return $browser.isMock ? update : function(){ if (!scheduled) { diff --git a/src/service/xhr.bulk.js b/src/service/xhr.bulk.js index d7fc7990..816336f8 100644 --- a/src/service/xhr.bulk.js +++ b/src/service/xhr.bulk.js @@ -82,6 +82,6 @@ angularServiceInject('$xhr.bulk', function($xhr, $error, $log){ } }); }; - this.$onEval(PRIORITY_LAST, bulkXHR.flush); + this.$observe(bulkXHR.flush); return bulkXHR; }, ['$xhr', '$xhr.error', '$log']); |
