数据过多(页面交互不流畅)-web worker+ ahooks解决

需求: 店铺选择器(h5端)

项目: reactHooks + antdMobile + mobx6

如下图:

image.png

image.png

大概就是这样一个大分组(品牌)下面有很多个品牌列表,每一个品牌有很多店铺, 需求就是选中店铺存到已选门店那里.这里使用了mbox存储.

细化:

  1. 每一个小分组下 全选反选功能,反选的时候只能删除该分组下的店铺
  2. 弹窗内清空按钮 - 全部清空
  3. 弹窗内 取消选中-删除单个
  4. 点击到不同的二级分组下,需要检验该分组内的店铺有没有被选中的,都被选中则全选

因为店铺过多在进行js操作的时候会造成卡顿.

解决: 大数据页面渲染问题

这里使用了 # useVirtualList 提供虚拟化列表能力的 Hook,用于解决展示海量数据渲染时首屏渲染缓慢和滚动卡顿问题。
官网地址: https://ahooks.gitee.io/zh-CN/hooks/use-virtual-list

 // 列表店铺数据
  const [virtual_list] = useVirtualList( state.shopSearchRes || [], {
    containerTarget: containerRef,
    wrapperTarget: wrapperRef,
    itemHeight: 30,
    overscan: 500
  })  

     <Checkbox.Group
        value={values}
        onChange={v => {
          setValues(v as string[])
        }}
      >
      { virtual_list && virtual_list.map((x: any ,index: any) => {
        return (
            <li key={x.data?.id } style={{height: '56px'}}>
              <div className="text">
                <span>{x.data.name}</span>
                <p>店铺编码{x.data.sn}|系统编码{x.data.id}</p>
              </div>
                <Checkbox  
                  // checked={store.storeSelection.storeSelectionData.includes(x)}
                  onChange={(val) => {
                    if (val) {
                      store.storeSelection.AddSelectionData(JSON.parse(JSON.stringify(x)).data)
                    }else {
                      // store.storeSelection.ReduceSelectionData([JSON.parse(JSON.stringify(x)).data])
                      worker.postMessage({ type: 'delcompute', payload: { 'data': [JSON.parse(JSON.stringify(x.data))], 'storeSelectionData': JSON.parse(JSON.stringify(store.storeSelection.storeSelectionData))}}) // 发送信息给worker
                    }
                  }}
                  key={x}
                  value={x.data.name}
                  style={{
                    '--icon-size': '15px',
                    '--font-size': '14px',
                    '--gap': '6px',
                  }}/>
            </li>
        )
        })}
        </Checkbox.Group>

进行js操作卡顿问题解决- # web worker

为什么JavaScript是单线程?

众所周知,JavaScript语言的特点是单线程,也就是说,同一个时间只能做一件事。那么,为什么JavaScript不能有多个线程呢?这样能提高效率啊。

JavaScript的单线程,与它的用途有关。作为浏览器脚本语言,JavaScript的主要用途是与用户互动,以及操作DOM。这决定了它只能是单线程,否则会带来很复杂的同步问题。比如,假定JavaScript同时有两个线程,一个线程在某个DOM节点上添加内容,另一个线程删除了这个节点,这时浏览器应该以哪个线程为准?

什么是Web Worker?

为了利用多核CPU的计算能力,HTML5提出Web Worker标准,允许JavaScript脚本创建多个线程,但是子线程完全受主线程控制,且不得操作DOM。所以,这个新标准并没有改变JavaScript单线程的本质。

在worker线程中,虽然无法直接操作dom节点,也不能使用window对象的默认方法属性,但是仍然可以使用window对象下的东西,比如websocketindexedDB等。

workers主线程间的数据传递通过这样的消息机制进行——双方都使用postMessage() 方法发送各自的消息,使用 onmessage 事件处理函数来响应消息(消息被包含在Message事件的 data 属性中)。这个过程中数据并不是被共享而是被复制。

关于web worker的兼容性问题,在can i use中查找一轮后发现,基本目前所有主流的浏览器都支持了,因此放心食用,无需考虑兼容性的问题。

image.png

例子:
该需求中删除选中店铺

  在tsx页面中
  
  const worker = new Worker(webWorker)
  worker.onmessage = function (e: { data: { type: string; msg: { newArr: any; valArr: any; }; }; }) {
    if (e.data.type === "delcompute") {
      const { newArr, valArr } = e.data.msg
      // newArr = newArr
      setValues(valArr)
      store.storeSelection.ReduceSelectionData(newArr)
    }
  } 
  
  调用的时候:
      // 取消全选选中
       <Checkbox
          style={{
            '--icon-size': '15px',
            '--font-size': '14px',
            '--gap': '6px',
          }}
          indeterminate={values.length > 0 && values.length < items.length}
          checked={ values?.length && values?.length === (items && items?.length)}
          onChange={checked => {                        
            if (checked) {
              // values.push(items)
              setValues(items)
              store.storeSelection.SetShopName(items)
              store.storeSelection.AddSelectionData(state.shopSearchRes)
            } else {
              setValues([])
              // store.storeSelection.ReduceSelectionData(state.shopSearchRes)
             worker.postMessage({ type: 'delcompute', payload: { 'data': JSON.parse(JSON.stringify(state.shopSearchRes)), 'storeSelectionData': JSON.parse(JSON.stringify(store.storeSelection.storeSelectionData))}}) // 发送信息给worker
            }
          }}
        >
          全选
        </Checkbox>
        
    // 取消单个选中
      <div className='text-29' onClick={() => {
          worker.postMessage({ type: 'delcompute', payload: { 'data': [JSON.parse(JSON.stringify(x.data))], 'storeSelectionData': JSON.parse(JSON.stringify(store.storeSelection.storeSelectionData))}}) // 发送信息给worker
          const aa = values.map( (item:any) => item !== x.data?.name)
        }}>取消选中</div>
      </li>
       
// webworker.js

const workercode = () => {
  // 监听事件,主线程可以通过 postMessage 发送信息过来
    // eslint-disable-next-line no-restricted-globals
    self.onmessage = function (e) {
      let passBack = void 0
      if (e.data.type === 'delcompute') {
        const { data , storeSelectionData } = e.data.payload 
        let newArr= storeSelectionData.filter((v) =>
        data.every((val) => val.id !== v.id)
        )
        const valArr = newArr.map(item => item.name)
        passBack = { newArr: newArr, valArr: valArr  }       
        // eslint-disable-next-line no-restricted-globals
        self.postMessage({
          type: 'delcompute',
          msg: passBack
        })
      } 
    }
  }
  
  let code = workercode.toString()
  code = code.substring(code.indexOf('{') + 1, code.lastIndexOf('}'))
  const blob = new Blob([code], {
    type: 'application/javascript'
  })
  const worker_script = URL.createObjectURL(blob)
  
  module.exports = worker_script
  

注意事项

虽然web worker可以调用cpu的多线程,从而提高咱们页面的性能。但是它不是随便使用的,如果滥用web worker可能不仅不会得到性能的提升,还可能造成性能的损耗

举一个简单的小栗子

如果咱们将递归获取斐波那契数列第n位的方法,将传入参数修改为第2位,这时候咱们再重跑单线程测试和多线程测试。

结果如下图,咱们可以发现单线程模式下,获取20次斐波那契数列第二位的时间仅需要1.5ms,而在多线程的情况下却需要78ms。这是为什么呢?因为咱们每次创建worker线程以及possmessage通信都是需要损耗一些性能以及时间的。因此web worker是不可以滥用的哦,日常开发中,建议在需要消耗比较多的cpu运算能力的时候酌情使用。

image.png

参考: https://juejin.cn/post/7117774868187185188

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值