Просмотр исходного кода

remove redundant dependencies for computed properties

Evan You 12 лет назад
Родитель
Сommit
76ee306bdf
3 измененных файлов с 83 добавлено и 64 удалено
  1. 5 1
      src/binding.js
  2. 58 58
      src/directive.js
  3. 20 5
      src/seed.js

+ 5 - 1
src/binding.js

@@ -1,7 +1,11 @@
 var Emitter  = require('emitter')
 
 /*
- *  Binding class
+ *  Binding class.
+ *
+ *  each property on the scope has one corresponding Binding object
+ *  which has multiple directive instances on the DOM
+ *  and multiple computed property dependents
  */
 function Binding (value) {
     this.value = value

+ 58 - 58
src/directive.js

@@ -9,66 +9,9 @@ var KEY_RE          = /^[^\|<]+/,
     INVERSE_RE      = /^!/,
     NESTING_RE      = /^\^+/
 
-/*
- *  parse a key, extract argument and nesting/root info
- */
-function parseKey (rawKey) {
-
-    var res = {},
-        argMatch = rawKey.match(ARG_RE)
-
-    res.key = argMatch
-        ? argMatch[2].trim()
-        : rawKey.trim()
-
-    res.arg = argMatch
-        ? argMatch[1].trim()
-        : null
-
-    res.inverse = INVERSE_RE.test(res.key)
-    if (res.inverse) {
-        res.key = res.key.slice(1)
-    }
-
-    var nesting = res.key.match(NESTING_RE)
-    res.nesting = nesting
-        ? nesting[0].length
-        : false
-
-    res.root = res.key.charAt(0) === '$'
-
-    if (res.nesting) {
-        res.key = res.key.replace(NESTING_RE, '')
-    } else if (res.root) {
-        res.key = res.key.slice(1)
-    }
-
-    return res
-}
-
-/*
- *  parse a filter expression
- */
-function parseFilter (filter) {
-
-    var tokens = filter.slice(1)
-        .match(FILTER_TOKEN_RE)
-        .map(function (token) {
-            return token.replace(/'/g, '').trim()
-        })
-
-    return {
-        name  : tokens[0],
-        apply : filters[tokens[0]],
-        args  : tokens.length > 1
-                ? tokens.slice(1)
-                : null
-    }
-}
-
 /*
  *  Directive class
- *  represents a single instance of DOM-data connection
+ *  represents a single directive instance in the DOM
  */
 function Directive (directiveName, expression) {
 
@@ -148,6 +91,63 @@ Directive.prototype.applyFilters = function (value) {
     return filtered
 }
 
+/*
+ *  parse a key, extract argument and nesting/root info
+ */
+function parseKey (rawKey) {
+
+    var res = {},
+        argMatch = rawKey.match(ARG_RE)
+
+    res.key = argMatch
+        ? argMatch[2].trim()
+        : rawKey.trim()
+
+    res.arg = argMatch
+        ? argMatch[1].trim()
+        : null
+
+    res.inverse = INVERSE_RE.test(res.key)
+    if (res.inverse) {
+        res.key = res.key.slice(1)
+    }
+
+    var nesting = res.key.match(NESTING_RE)
+    res.nesting = nesting
+        ? nesting[0].length
+        : false
+
+    res.root = res.key.charAt(0) === '$'
+
+    if (res.nesting) {
+        res.key = res.key.replace(NESTING_RE, '')
+    } else if (res.root) {
+        res.key = res.key.slice(1)
+    }
+
+    return res
+}
+
+/*
+ *  parse a filter expression
+ */
+function parseFilter (filter) {
+
+    var tokens = filter.slice(1)
+        .match(FILTER_TOKEN_RE)
+        .map(function (token) {
+            return token.replace(/'/g, '').trim()
+        })
+
+    return {
+        name  : tokens[0],
+        apply : filters[tokens[0]],
+        args  : tokens.length > 1
+                ? tokens.slice(1)
+                : null
+    }
+}
+
 module.exports = {
 
     /*

+ 20 - 5
src/seed.js

@@ -83,6 +83,7 @@ function Seed (el, options) {
     // extract dependencies for computed properties
     parsingDeps = true
     this._computed.forEach(parseDeps)
+    this._computed.forEach(injectDeps)
     delete this._computed
     parsingDeps = false
 }
@@ -266,19 +267,33 @@ Seed.prototype._dump = function () {
 
 /*
  *  Auto-extract the dependencies of a computed property
- *  by recording the getters triggered when evaluating it
+ *  by recording the getters triggered when evaluating it.
+ *
+ *  However, the first pass will contain duplicate dependencies
+ *  for computed properties. It is therefore necessary to do a
+ *  second pass in injectDeps()
  */
 function parseDeps (binding) {
+    binding.dependencies = []
     depsObserver.on('get', function (dep) {
-        if (!dep.dependents) {
-            dep.dependents = []
-        }
-        dep.dependents.push.apply(dep.dependents, binding.instances)
+        binding.dependencies.push(dep)
     })
     binding.value.get()
     depsObserver.off('get')
 }
 
+/*
+ *  The second pass of dependency extraction.
+ *  Only include dependencies that don't have dependencies themselves.
+ */
+function injectDeps (binding) {
+    binding.dependencies.forEach(function (dep) {
+        if (!dep.dependencies || !dep.dependencies.length) {
+            dep.dependents.push.apply(dep.dependents, binding.instances)
+        }
+    })
+}
+
 /*
  *  determine which scope a key belongs to based on nesting symbols
  */