感兴趣的可以去MDN官网,查看Web Worker API,Web开发技术-Web API接口参考-Web Worker API

Web Worker API

1、 Web Worker 使得在一个独立于 Web 应用程序主执行线程的后台线程中运行脚本操作成为可能。这样做的好处是可以在独立线程中执行费时的处理任务,使主线程(通常是 UI 线程)的运行不会被阻塞/放慢。
2、Worker 是一个使用构造函数创建的对象(例如 Worker()),它运行一个具名 JavaScript 文件——该文件包含将在 worker 线程中运行的代码。
3、可以在 worker 线程中运行任何你喜欢的代码,有一些例外:你不能直接在 worker 线程中操作 DOM 元素,或使用 window 对象中的某些方法和属性
4、数据通过消息系统在 worker 和主线程之间发送——双方都使用 postMessage() 方法发送消息,并通过 onmessage 事件处理程序响应消息(消息包含在 message 事件的 data 属性中)。数据是复制的,而不是共享的。

以简单的方式理解web work:
1、创建 Worker:在 JavaScript 中,使用 new Worker() 函数创建一个 Web Worker。需要传递一个 JavaScript 文件的 URL 作为参数,该文件将被用作 Worker 的脚本
2、启动 Worker:调用 worker.postMessage() 方法向 Worker 发送消息。可以通过该方法传递任意类型的数据给 Worker。Worker 可以通过 onmessage 事件监听来接收这些消息
3、Worker 执行:Worker 在后台线程中执行脚本。Worker 的代码在独立的全局作用域中运行,并且无法访问 DOM 和其他浏览器 API,因此它不会干扰主线程的运行
4、处理消息:Worker 可以通过 onmessage 事件监听来接收主线程发送的消息。通过 event.data 属性可以获取到接收到的数据。Worker 可以在接收到消息后执行相应的操作,并使用 postMessage() 方法向主线程发送处理结果。
5、结束 Worker:当不再需要 Worker 时,可以调用 worker.terminate() 方法来终止 Worker 的执行

//主线程
var worker =  new Worker('work.js')

worker.onmessage = e=>{
console.log(e.data)
}
//Worker线程
//做一些耗时的操作
self.postMessage('worker'+result)

关于self:

在 Web Worker 中,self 是一个指向 Worker 自身的全局对象。可以将 self 用作替代 this 关键字来引用当前 Worker 线程的全局对象。通过 self 对象,Worker 可以访问一些全局属性和方法,以及与主线程之间的通信接口。如:self.location、self.close()、self.postMessage()

1、主线程—表格列宽改变

      <vxe-table      
        border
        :align="'center'"      
        resizable     
        @resizable-change="resizableChange"
      >
  resizableChange({ column }) {
      const copyColumns = JSON.stringify(this.newColumns)
      const columnData = JSON.stringify(column)
      return new Promise((resolve, reject) => {
      //1、主线程实例化了一个新的 Worker 对象,并指定了 Worker 脚本文件的 URL 为 '/worker.js'
        const worker = new Worker('/worker.js')
      //2、主线程设置了 Worker 对象的 onmessage 和 onerror 事件监听器,分别用于接收来自 Worker 线程的消息和处理错误
        worker.onmessage = e => {
          const { result } = e.data
          resolve(result)
          //当不再需要 Worker 时,可以调用 worker.terminate() 方法来终止 Worker 的执行
          worker.terminate()
        }
        worker.onerror = e => {
          reject(e)
            //当不再需要 Worker 时,可以调用 worker.terminate() 方法来终止 Worker 的执行
          worker.terminate()
        }
        setTimeout(() => {
          reject(new Error('worker请求超时!'))
           //当不再需要 Worker 时,可以调用 worker.terminate() 方法来终止 Worker 的执行
          worker.terminate()
        }, 3000)
        //通过 worker.postMessage() 向 Worker 发送了一个包含 method、copyColumns 和 columnData 的消息
        worker.postMessage({ method: 'ClassAResizableChange', copyColumns: copyColumns, column: columnData })
      })
        .then(result => {
          this.newColumns = result
          setTimeout(() => {
            this.$nextTick(() => {
              this.$refs.vxeTable.scrollTo(this.scrollLeft)
            })
          }, 500)
        })
        .catch(error => {
          console.error(error)
        })
    },

2、主线程—表格列拖拽

  mounted() {
    this.$nextTick(() => {
      this.columnDrop()
    })
  },
  updated() {
    this.$nextTick(() => {
      this.columnDrop()
    })
  },
    columnDrop() {
const wrapperTr = document.querySelector('.body--wrapper>.vxe-table--header .vxe-header--row')
this.sortable = Sortable.create(wrapperTr, {
animation: 220,
delay: 0,
filter: '.vxe-header--column .vxe-cell',
draggable: '.vxe-header--column',
easing: 'cubic-bezier(1, 0, 0, 1)',
onStart: () => {},
onEnd: evt => {
const { oldIndex, newIndex } = evt
const empty = 2
const copyColumns = JSON.stringify(this.newColumns)
return new Promise((resolve, reject) => {
//1、主线程实例化了一个新的 Worker 对象,并指定了 Worker 脚本文件的 URL 为 '/worker.js'
const worker = new Worker('/worker.js')
//2、主线程设置了 Worker 对象的 onmessage 和 onerror 事件监听器,分别用于接收来自 Worker 线程的消息和处理错误
worker.onmessage = e => {
const { result } = e.data
resolve(result)
//当不再需要 Worker 时,可以调用 worker.terminate() 方法来终止 Worker 的执行
worker.terminate()
}
worker.onerror = e => {
reject(e)
//当不再需要 Worker 时,可以调用 worker.terminate() 方法来终止 Worker 的执行
worker.terminate()
}
setTimeout(() => {
reject(new Error('worker请求超时!'))
//当不再需要 Worker 时,可以调用 worker.terminate() 方法来终止 Worker 的执行
worker.terminate()
}, 3000)
//通过 worker.postMessage() 向 Worker 发送了一个包含 method、copyColumns 和  oldIndex, newIndex, empty 的消息
worker.postMessage({ method: 'ClassAColumnDrop', copyColumns, oldIndex, newIndex, empty })
})
.then(result => {
this.newColumns = result
const data = {
styleJson: this.newColumns,
tableId: this.vxeTableId,
}
this.savStyle(data).then(res => {
if (this.scrollLeft === undefined) {
return
}
setTimeout(() => {
this.$nextTick(() => {
this.$refs.vxeTable.scrollTo(this.scrollLeft)
})
}, 500)
})
})
.catch(error => {
console.error(error)
})
},
})
},

3、worker线程
新建work.js,放在public或static等静态文件夹下,public/work.js

关于work.js为什么要放在public或static静态文件夹下:

worker.js 脚本文件需要被浏览器访问到,并且在主线程中通过 new Worker() 方法来创建一个新的 Worker 线程。因此,需要将 worker.js 放置于可以被浏览器访问到的位置。

在 Vue.js 项目中,public 和 static 文件夹都属于静态资源目录,这些文件夹下的内容不会被 webpack
处理,而是直接复制到输出目录中。因此,将 worker.js 放置于 public 或 static
文件夹下,可以让浏览器能够直接访问到这个文件,并在主线程中使用 new Worker(‘/worker.js’) 来创建一个新的
Worker 实例。

需要注意的是,如果将 worker.js 放置于其他目录下,可能会导致浏览器无法访问到该文件,从而无法创建 Worker
线程。同时,如果放置的位置不当,还可能影响应用程序的性能或安全性。因此,在将 worker.js 放置于 public 或 static
文件夹下时,需要注意设置正确的访问路径和访问权限

//使用 self.onmessage 监听主线程发送的消息,并根据消息中的 method 执行不同的处理函数。
self.onmessage = function (event) {
const { method, copyColumns } = event.data
let result = []
const parsedColumns = JSON.parse(copyColumns)
switch (method) {
case 'ClassAResizableChange':
result = parseClassAResizableChange(parsedColumns, event.data.column)
break
case 'ClassAColumnDrop':
result = parseClassAColumnDrop(parsedColumns, event.data.oldIndex, event.data.newIndex, event.data.empty)
break
}
//Worker 线程处理完毕后,通过 self.postMessage() 将处理结果发送回主线程
self.postMessage({ result })
}
function parseClassAResizableChange(columns, column) {
const parsedColumn = JSON.parse(column)
const resizableDataMap = new Map()
resizableDataMap.set(parsedColumn.field, {
resizeWidth: parsedColumn.resizeWidth,
})
for (let i = 0; i < columns.length; i++) {
const column = columns[i]
const resizableColumn = resizableDataMap.get(column.field)
if (resizableColumn) {
column.width = resizableColumn.resizeWidth
}
}
return columns
}
function parseClassAColumnDrop(columns, oldIndex, newIndex, empty) {
const oldItem = columns[oldIndex - empty]
columns.splice(oldIndex - empty, 1)
columns.splice(newIndex - empty, 0, oldItem)
columns.sort((a, b) => b.freeze - a.freeze)
return columns
}
本站无任何商业行为
个人在线分享 » web worker性能优化,vxe-table提高表格列拖拽和列宽改变等操作的性能,具体实现详解
E-->