vue-worker的介紹和使用

vue-worker把複雜的web worker封裝起來,提供一套很是簡明的api接口,使用的時候能夠說像不接觸worker同樣方便。那麼具體怎麼使用呢?javascript

安裝

npm i -S vue-worker

 

註冊

import Vue from 'vue'import VueWorker from 'vue-worker'import App from 'App.vue'
Vue.use(VueWorker)
new Vue({
   el: '#app',
  render: h => h(App) })
註冊以後,你能夠像this.$store同樣使用this.$worker

使用

export default {
 name: 'worker-test', data() {
   return {
    worker: null,
   }
 },
 mounted() {
   // 經過this.$worker.run這個方法,跑起一個worker,
   // worker是在另外的線程裏面跑的,因此能夠在run的第一個參數函數裏面執行一個很是大計算的操做
   // run方法像Promise同樣提供.then和.catch,then的參數就是run第一個參數函數的返回值
   this.worker = this.$worker.run(n => n + 10, [2])
    .then(res => console.log(res))
    .catch(e => console.log(e)) }, destroyed() {
   // 經過賦值null的方式,釋放掉worker引用,這樣就能夠關閉worker,這是做者在github上說的
   this.worker = null
 },
}

 

API介紹

下面來詳細介紹一下vue-worker的幾個api,也就是方法method。vue

.run(fun, [...args])

上面已經看到了這個方法,並且也有註釋說明。注意第二個參數是一個數組,數組的個數和第一個參數fun的形參個數是同樣的。
你可能會有一個疑問:直接在fun函數體內使用當前變量不就行了麼?js自己的全局變量特性在這裏不能用?這是由於worker是在另一個線程中運行,跟當前頁面內的js腳本不是在同一個線程,不共享內存空間,因此直接在fun函數體裏面使用另一個線程的變量是找不到的,因此要經過函數參數的形式進行傳遞。而傳遞的實質,是使用了worker的postMessage方法,把第二個參數當作postMessage的內容,具體你能夠閱讀這裏的源碼。java

run是一次性的,跑完此次,worker線程就會被關掉。想要持久化worker,能夠使用下面的create來建立。git

.create([...actions])

這個方法讓你建立一個worker對象(注意不是worker實例,你沒法經過該對象直接操做worker,這個實例僅僅是一個js object,提供了幾個屬性接口)。github

actions是一個數組,數組的每一個元素是一個含有兩個屬性的對象:web

export default {
  name: 'worker-test',
  data() {
    return {
     worker: null,
    }
  },
  created() {
    this.worker = this.$worker.create([
      {
        message: 'pull-data',
        func(data) {
          data.forEach(...)
          return data
        },
      },
      {
        message: 'run-task',
        func(id) {
          //...
        },
      }
    ])
  },
  mounted() {
    let data = ...
    this.worker.postMessage('pull-data', [data])
      .then(res => console.log(res))
  },
  destroyed() {
    this.worker = null
  },
}

實際上.run方法是create方法和postMessage方法的合體,一次性把兩個方法的事都作了。npm

.postMessage(messageid, [...args])

這個在上面的代碼裏面已經演示了。它不是this.$worker的方法,而是經過this.$worker.create以後獲得的object的一個方法。使用這個方法跟worker原生的方法很像,固然,這裏的messageid就是上面actions數組裏面的某個對象的message字段對應的那個。而args就是你要傳遞的數據。api

你可能又會問了,這裏的[..args]是一個參數,仍是說裏面的元素纔是參數。其實很簡單,[...args]被用做了.apply的第二個參數:func.apply(null, [...args]),因此,...args對應的就是func的參數。數組

.postAll([...args])

這裏的postAll和上面的postMessage同樣,是create以後的那個object的一個方法,而不是this.$worker的,因此使用的時候,也只能用在create以後。瀏覽器

它的參數是一個數組,可是這個數組的元素有三種形式,一種是不傳,一種是string:messageid,另外一種是{message, [...func_args]}。其實都很好理解。

不傳

表明全部的actions都執行一次postMessage。

[string:messageid]

表明對應的messageid的那個action被執行postMessage。

[{message, [...func_args]}]

給指定的messageid傳參數。

export default {
  name: 'worker-test',
  data() {
    return {
      worker: null,
    }
  },
  created() {
    this.worker = this.$worker.create([
      {
        message: 'pull-data',
        func(data) {
          data.forEach(...)
          return data
        },
      },
      {
        message: 'run-task',
        func() {
          //...
        },
      }
    ])
  },
  mounted() {
  
    // 1. 不傳
    this.worker.postAll().then([res1, res2] => {})
  
    // 2. 字符串形式
    let data = ...
    this.worker.postAll(['run-task']).then([res] => {}) // 僅'run-task'被postMessage
  
    // 3. 對象形式(混合形式)
    this.worker.postAll([
      'run-task',
      {
        message: 'pull-data',
        args: [data],
      },
    ]).then([res1, res2] => {})
  },
  destroyed() {
    this.worker = null
  },
}

 

比較難把握的就是,這裏全部的傳入都要採用數組的形式,理解上須要稍微思考下。

.register(action || [...actions])

同理,也是在<worker>的object對象上的方法。當你使用create以後,發現你的worker任務不夠用,要追加一個action或多個,那麼能夠使用register來追加。action(s)和create是如出一轍的。

.unregister(message || [...messages])

和register有點像,意思是當你某一個任務不想要了,能夠經過unregister來取消這個任務。參數和register不同,直接使用messageid做爲參數便可。

export default {
  name: 'worker-test',
  data() {
    return {
      worker: null,
    }
  },
  created() {
    this.worker = this.$worker.create([
      {
        message: 'pull-data',
        func(data) {
          data.forEach(...)
          return data
        },
      },
      {
        message: 'run-task',
        func() {
          //...
        },
      }
    ])
  },
  mounted() {
    // 1. 不傳
    this.worker.postAll().then([res1, res2] => {})
  
    // 2. 字符串形式
    let data = ...
    this.worker.postAll(['run-task']).then([res] => {}) // 僅'run-task'被postMessage
  
    // 3. 對象形式(混合形式)
    this.worker.postAll([
      'run-task',
      {
        message: 'pull-data',
        args: [data],
      },
    ]).then([res1, res2] => {
      // 注意,這裏then裏面執行的是在主js線程裏面執行的,因此能夠直接用this.worker
      this.worker.unregister('run-task')
      // 當你註銷掉了,那麼下回你在post到run-task這個任務消息時,就啥都不會發生了
    })
  },
  destroyed() {
    this.worker = null
  },
}

關閉worker

在最前面的代碼裏面已經提到了,插件的做者指出,你是沒辦法拿到worker原始實例的,因此也就沒法調用worker.terminate()或者在worker線程內部執行self.close()來關閉worker。create方法建立的不是worker實例,因此它內部有,可是沒有暴露出來。因此插件沒有關閉worker的方法,你直接把worker對象釋放掉便可。我翻閱了源碼,發現它只在調用run方法時才使用close,執行完run以後worker會被close,可是若是你使用create建立的worker,是不會被close的它會一直存在,直到你關閉瀏覽器。

原理

web worker是經過一個瀏覽器提供的Worker對象來建立的,建立的時候要傳入指定的javascript文件做爲worker線程的執行腳本。worker線程內的腳本有一些限制,好比只能拿到window.navigator的信息,不能拿到完整的window對象。重點是,這裏咱們沒有提供一個js文件傳入worker線程,vue-worker是怎麼作到的呢?它利用了Blob來建立一個可執行的二進制上下文,在經過這個上下文來調用咱們傳入的function,就好像在內存中虛擬了一個內容是咱們傳入的function的js文件同樣。具體的源碼能夠看這裏

相關文章
相關標籤/搜索