Vue.js中方法的怪异行为

时间:2019-01-23 04:25:52

标签: javascript vue.js webpack

我的应用程序中有一个data变量,它是message,并且在执行某些加密算法的方法中也有一种方法。 这是我的代码。

export default {
  data: () => ({
    message: ""
  }),
  methods: {
    click() {
      this.message = "Hello";
      console.log("this.message ", this.message); // Prints "Hello"

      // takes around 8 seconds
      var encryptedPassphrase = generateKeystore();
      console.log("this.message ", this.message); // Prints "Hello"
    }
  }
};

我在HTML标记中显示的message变量上方,并且从Vuetify按钮调用了方法click。 下面是HTML代码,

<div>
    <p>{{message}}</p>
    <v-btn @click="click">Click</v-btn>
</div>

问题
现在的问题是,当调用click方法的第一个任务时,它要做的是更新message变量,但是完成完整功能执行后,此message变量更新会反映在HTML中。因此,在click函数中,下一个任务是加密计算,该过程大约需要8秒钟,完成后message将以HTML反映。我不知道这是怎么回事。 只需提及我在这里使用webpack

更新

  <v-btn @click="update(); click();">Click</v-btn>

即使这不起作用,这里的update方法也会更新message变量,它会在click函数完成后进行更新。

2 个答案:

答案 0 :(得分:1)

如果希望click方法中更改的消息数据字段在方法完成之前反映在html中,则必须将加密函数包装在Vue.nextTick中。这样可以确保nextTick内部的逻辑将在下一个DOM更新周期执行。这将使DOM被更新为消息的最新值,然后它将执行加密功能。否则,Vue将等待单击功能完成,然后更改才会反映在DOM中。

Vue.nextTick(function() { //cryptographic function })

https://vuejs.org/v2/api/#Vue-nextTick

答案 1 :(得分:0)

长话短说,在这种情况下,您应使用Web Worker处理诸如generateKeystore函数之类的任务。您的message未被渲染的原因是一次只能执行一个Javascript,基本上您的generateKeystore会阻止Vue渲染(观察程序等),直​​到完成为止。

我创建了一个js小提琴来演示Vue-Web Worker的用法https://jsfiddle.net/Fourzero/t9L1g2hj/17/。您也可以在下面找到代码。在此示例中,click处理程序遇到了与您描述的问题相同的消息(更改的消息只有在执行慢速功能后才会呈现),click2方法以message的方式对其进行处理“ hello”立即被渲染,并且慢速函数开始执行(需要几秒钟),完成后将返回值。

HTML

<script id="worker1" type="javascript/worker">

  // This script won't be parsed by JS engines because its type is javascript/worker.
  self.onmessage = function(e) {
    console.log('slow function started execution inside worker with parameter: ', e.data)
    // execute slow function
    var sum = 1;
        for (let i = 1; i < 10000000000; i++) {
        sum = sum + i;
    }
    console.log('DONE!!slow function finished inside worker with result: ' + sum)
    self.postMessage(sum);
  };

</script>


<div id="app">
    <p ref="message">{{message}}</p>
    <p >slowFunctionResult: {{slowFunctionResult}}</p>
    <button @click="click">Click</button>
    <button @click="click2">Click (Run in worker)</button>
</div>

Javascript

var blob = new Blob([
  document.querySelector('#worker1').textContent
], { type: "text/javascript" })

// Note: window.webkitURL.createObjectURL() in Chrome 10+.
var worker = new Worker(window.URL.createObjectURL(blob));


new Vue({
  el: '#app',
  data: {
    message: 'xx',
    slowFunctionResult: ''
  },

  methods: {
    click() {
      this.message = 'hello';
      console.log("slow function start")
      this.slowFunction();
      console.log("slow function done")

      // the next tick won't happen until the slow function finished
    },

    click2() {
      this.message = 'hello';

      let that = this;
      worker.onmessage = function(e) {
        console.log("Received result from worker!: " + e.data);
        that.slowFunctionResult = e.data;
      }
      // DOM should be updated before the slow function execution finished
      worker.postMessage(this.message); // Start the worker.
    },


    slowFunction() {
        var sum = 1;
        for (let i = 1; i < 10000000000; i++) {
            sum = sum + i;
        }
    }
  }
})

单击Click (Run in worker)按钮的控制台输出

slow function started execution inside worker with parameter:  hello
// after a few seconds
DONE!!slow function finished inside worker with result: 49999999990067860000
Received result from worker!: 49999999990067860000