Quellcode durchsuchen

Async fixes
- vm.$watch is now async
- v-model now unlocks async (so it is properly locked during async update)
- expose Vue.nextTick

Evan You vor 12 Jahren
Ursprung
Commit
c71a9085a7
6 geänderte Dateien mit 68 neuen und 27 gelöschten Zeilen
  1. 3 1
      src/directives/model.js
  2. 1 0
      src/main.js
  3. 10 2
      src/viewmodel.js
  4. 10 6
      test/functional/specs/todomvc.js
  5. 5 2
      test/unit/specs/misc.js
  6. 39 16
      test/unit/specs/viewmodel.js

+ 3 - 1
src/directives/model.js

@@ -53,7 +53,9 @@ module.exports = {
                 // no filters, don't let it trigger update()
                 self.lock = true
                 self.vm.$set(self.key, el[attr])
-                self.lock = false
+                utils.nextTick(function () {
+                    self.lock = false
+                })
             }
         el.addEventListener(self.event, self.set)
 

+ 1 - 0
src/main.js

@@ -66,6 +66,7 @@ ViewModel.transition = function (id, transition) {
 }
 
 ViewModel.extend = extend
+ViewModel.nextTick = utils.nextTick
 
 /**
  *  Expose the main ViewModel class

+ 10 - 2
src/viewmodel.js

@@ -37,7 +37,15 @@ def(VMProto, '$set', function (key, value) {
  *  fire callback with new value
  */
 def(VMProto, '$watch', function (key, callback) {
-    this.$compiler.observer.on('change:' + key, callback)
+    var self = this
+    function on () {
+        var args = arguments
+        utils.nextTick(function () {
+            callback.apply(self, args)
+        })
+    }
+    callback._fn = on
+    self.$compiler.observer.on('change:' + key, on)
 })
 
 /**
@@ -49,7 +57,7 @@ def(VMProto, '$unwatch', function (key, callback) {
     // by checking the length of arguments
     var args = ['change:' + key],
         ob = this.$compiler.observer
-    if (callback) args.push(callback)
+    if (callback) args.push(callback._fn)
     ob.off.apply(ob, args)
 })
 

+ 10 - 6
test/functional/specs/todomvc.js

@@ -16,7 +16,12 @@ casper.test.begin('todomvc', 69, function (test) {
     // let's add a new item -----------------------------------------------
 
     .then(function () {
-        createNewItem('test')
+        casper.sendKeys('#new-todo', 'test')
+    })
+    .then(function () {
+        // wait before hitting enter
+        // so v-model unlocks
+        createNewItem()
     })
     .then(function () {
 
@@ -31,10 +36,7 @@ casper.test.begin('todomvc', 69, function (test) {
         test.assertVisible('#main', '#main should now be visible')
         test.assertVisible('#footer', '#footer should now be visible')
         test.assertNotVisible('#clear-completed', '#clear-completed should be hidden')
-
-        test.assertEvalEquals(function () {
-            return __utils__.findOne('#new-todo').value
-        }, '', 'new todo input should be reset')
+        test.assertField({type:'css',path:'#new-todo'}, '', 'new todo input should be reset')
 
     })
 
@@ -256,7 +258,9 @@ casper.test.begin('todomvc', 69, function (test) {
     // helper ===============
 
     function createNewItem (text) {
-        casper.sendKeys('#new-todo', text)
+        if (text) {
+            casper.sendKeys('#new-todo', text)
+        }
         casper.evaluate(function () {
             // casper.mouseEvent can't set keyCode
             var field = document.getElementById('new-todo'),

+ 5 - 2
test/unit/specs/misc.js

@@ -45,7 +45,7 @@ describe('Misc Features', function () {
     })
 
     describe('setting an object to empty', function () {
-        it('should emit undefined for paths in the old object', function () {
+        it('should emit undefined for paths in the old object', function (done) {
             var v = new Vue({
                 data: {
                     a: {
@@ -59,7 +59,10 @@ describe('Misc Features', function () {
                 emitted = true
             })
             v.a = {}
-            assert.ok(emitted)
+            nextTick(function () {
+                assert.ok(emitted)
+                done()
+            })
         })
     })
 

+ 39 - 16
test/unit/specs/viewmodel.js

@@ -26,16 +26,19 @@ describe('UNIT: ViewModel', function () {
 
     describe('.$watch()', function () {
 
-        it('should trigger callback when a plain value changes', function () {
+        it('should trigger callback when a plain value changes', function (done) {
             var val
             vm.$watch('a.b.c', function (newVal) {
                 val = newVal
             })
             data.b.c = 'new value!'
-            assert.strictEqual(val, data.b.c)
+            nextTick(function () {
+                assert.strictEqual(val, data.b.c)
+                done()
+            })
         })
 
-        it('should trigger callback when an object value changes', function () {
+        it('should trigger callback when an object value changes', function (done) {
             var val, subVal, rootVal,
                 target = { c: 'hohoho' }
             vm.$watch('a.b', function (newVal) {
@@ -47,31 +50,45 @@ describe('UNIT: ViewModel', function () {
             vm.$watch('a', function (newVal) {
                 rootVal = newVal
             })
+
             data.b = target
-            assert.strictEqual(val, target)
-            assert.strictEqual(subVal, target.c)
-            vm.a = 'hehehe'
-            assert.strictEqual(rootVal, 'hehehe')
+            nextTick(function () {
+                assert.strictEqual(val, target)
+                assert.strictEqual(subVal, target.c)
+                next()
+            })
+
+            function next () {
+                vm.a = 'hehehe'
+                nextTick(function () {
+                    assert.strictEqual(rootVal, 'hehehe')
+                    done()
+                })
+            }
+            
         })
 
-        it('should trigger callback when an array mutates', function () {
+        it('should trigger callback when an array mutates', function (done) {
             var val, mut
             vm.$watch('b', function (array, mutation) {
                 val = array
                 mut = mutation
             })
             arr.push(4)
-            assert.strictEqual(val, arr)
-            assert.strictEqual(mut.method, 'push')
-            assert.strictEqual(mut.args.length, 1)
-            assert.strictEqual(mut.args[0], 4)
+            nextTick(function () {
+                assert.strictEqual(val, arr)
+                assert.strictEqual(mut.method, 'push')
+                assert.strictEqual(mut.args.length, 1)
+                assert.strictEqual(mut.args[0], 4)
+                done()
+            })
         })
 
     })
 
     describe('.$unwatch()', function () {
         
-        it('should unwatch the stuff', function () {
+        it('should unwatch the stuff', function (done) {
             var triggered = false
             vm.$watch('a.b.c', function () {
                 triggered = true
@@ -87,7 +104,10 @@ describe('UNIT: ViewModel', function () {
             vm.$unwatch('a.b.c')
             vm.a = { b: { c:123123 }}
             vm.b.push(5)
-            assert.notOk(triggered)
+            nextTick(function () {
+                assert.notOk(triggered)
+                done()
+            })
         })
 
     })
@@ -477,7 +497,7 @@ describe('UNIT: ViewModel', function () {
             assert.strictEqual(vm.$data, data)
         })
 
-        it('should be able to be swapped', function () {
+        it('should be able to be swapped', function (done) {
             var data1 = { a: 1 },
                 data2 = { a: 2 },
                 vm = new Vue({data: data1}),
@@ -488,7 +508,10 @@ describe('UNIT: ViewModel', function () {
             })
             vm.$data = data2
             assert.equal(vm.a, 2)
-            assert.ok(emittedChange)
+            nextTick(function () {
+                assert.ok(emittedChange)
+                done()
+            })
         })
     })