最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

JS前端千萬(wàn)級(jí)彈幕數(shù)據(jù)循環(huán)優(yōu)化示例

 更新時(shí)間:2022年07月14日 16:21:32   作者:朽木白丶  
這篇文章主要為大家介紹了JS前端一千萬(wàn)條彈幕數(shù)據(jù)循環(huán)優(yōu)化示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

引言

最近做了直播相關(guān)的業(yè)務(wù),然后對(duì)于大數(shù)據(jù)相關(guān)的優(yōu)化做了一下復(fù)盤。

為了了解我是怎么做這個(gè)優(yōu)化的,我們先從如何按照特定的條件刪除一個(gè)數(shù)組說(shuō)起。

1、如何刪除數(shù)組中的元素

場(chǎng)景:有一個(gè)數(shù)組,需要?jiǎng)h除滿足條件的數(shù)組。

示例

const arr = [1,2,3,4,5,6,7,8]

刪除小于5的元素,刪除后的元素為

const arr2 = [5, 6, 7, 8]

代碼實(shí)現(xiàn):

const arr = [1,2,3,4,5,6,7,8]
for(let i = 0, len = arr.length; i < len; i++) {
	if(arr[i] < 5) {
		arr.splice(i, 1)
	}
}

結(jié)果如下

arr = [2, 4, 5, 6, 7, 8

不是我們預(yù)期的結(jié)果

分析原因:刪除操作會(huì)使得對(duì)應(yīng)索引值位上的元素清空,整個(gè)數(shù)組中的元素向前移動(dòng)一位,補(bǔ)位的元素會(huì)填充到執(zhí)行刪除操作的索引值位置上,移位之后如果不進(jìn)行任何操作繼續(xù)下一個(gè)循環(huán),會(huì)導(dǎo)致補(bǔ)位元素跳過(guò)遍歷,為了防止這種補(bǔ)位元素跳過(guò)遍歷現(xiàn)象,應(yīng)該在刪除操作后將索引值減1,對(duì)執(zhí)行刪除操作的索引值位置再進(jìn)行一次遍歷 。

改進(jìn):

const arr = [1,2,3,4,5,6,7,8]
for(let i = 0, len = arr.length; i < len; i++) {
	if(arr[i] < 5) {
		arr.splice(i, 1)
    i--;
	}
}
// arr = [5, 6, 7, 8] 符合預(yù)期

這個(gè)是做了正序循環(huán)刪除,也可以使用倒序循環(huán)刪除:

const arr = [1,2,3,4,5,6,7,8]
for(let i = arr.length - 1; i >= 0; i--) {
	if(arr[i] < 5) {
		arr.splice(i, 1)
	}
}
// arr = [5, 6, 7, 8] 符合預(yù)期

2、10000,000條消息如何優(yōu)化?

場(chǎng)景

彈幕消息發(fā)送場(chǎng)景模擬(偽直播形式,沒(méi)有進(jìn)度條):假設(shè)我們有10000,000條消息,根據(jù)視頻播放的進(jìn)度展示對(duì)應(yīng)的消息,不展示歷史消息。

常規(guī)思路:

循環(huán)遍歷整個(gè)消息列表,時(shí)刻監(jiān)聽(tīng)視頻播放的進(jìn)度,根據(jù)視頻播放的時(shí)間戳和消息發(fā)送的時(shí)間戳先相等,然后展示消息,依次循環(huán)。

產(chǎn)生的問(wèn)題

每次視頻進(jìn)度變化都會(huì)循環(huán)整個(gè)消息列表,當(dāng)循環(huán)還沒(méi)完成,下一個(gè)播放進(jìn)度監(jiān)聽(tīng)觸發(fā)了,又開始下一個(gè)循環(huán),這樣就會(huì)造成性能的損耗。

優(yōu)化策略

我們從上面的分析可以看出,當(dāng)消息發(fā)送了一條,就可以從原始數(shù)據(jù)刪除這條消息,然后跳出循環(huán),這樣循環(huán)的次數(shù)始終控制在幾次(或者幾十次)的范圍(有可能同一個(gè)時(shí)間段同時(shí)有幾條消息甚至幾十條消息)等下一個(gè)播放進(jìn)度監(jiān)聽(tīng)觸發(fā),開始循環(huán)原始數(shù)據(jù),這是之前以后發(fā)送過(guò)得數(shù)據(jù)刪除了,就不會(huì)再循環(huán)刪除過(guò)的數(shù)據(jù),始終循環(huán)需要發(fā)送的那幾條,找到了就直接跳出循環(huán)。

代碼實(shí)現(xiàn)

// 模擬原始消息列表,
const newList = new Array(10000000).fill(1).map((item, index) => {
  return {
    time: (index + 1) * 1000,       // 消息發(fā)送的時(shí)間,一秒一個(gè)
    content: `這是第${index + 1}s發(fā)送的消息` // 消息發(fā)送的內(nèi)容
  }
})
// 發(fā)送的消息列表
const sendList = [];
function getMessage(time) {
  let j = 0; // 循環(huán)次數(shù)
  for(let i = 0, len = newList.length; i < len; i++) {
    const item = newList[i];
    j++;
    // 這里的time如果不是1000、2000,而是1234、1214這種,就需要取一個(gè)浮動(dòng)范圍
    // 我這里就是簡(jiǎn)單用了定時(shí)器,所以比較簡(jiǎn)單
    if(item.time === time) {
      sendList.push(newList[i])
      newList.splice(i, 1)
      i--;
    } else if(sendList.length > 0) {
        break;
    }
  }
  console.log('播放進(jìn)度', time)
  console.log('循環(huán)的次數(shù)', j);
  console.log('接收的消息的長(zhǎng)度', sendList.length, sendList);
  console.log('原始消息的長(zhǎng)度', newList.length);
}
let time = 0;
// 定時(shí)器,1s觸發(fā)一次
setInterval(() => {
  time += 1000;
  getMessage(time);
}, 1000)
// 消息格式
newList = [
  {time: 1000, content: '這是第1s發(fā)送的消息'},
  {time: 2000, content: '這是第2s發(fā)送的消息'},
  ...
]

效果展示

小結(jié)

上面優(yōu)化策略只有兩條

發(fā)送過(guò)的消息刪除,下次少循環(huán)。

當(dāng)找到滿足條件的數(shù)據(jù),直接跳出循環(huán),后面的數(shù)據(jù)不再循環(huán)。

缺點(diǎn):使用slice也會(huì)消耗性能,不可取,并且操作繁瑣。

游標(biāo)法代替splice

我們這里不再使用slice的方案,設(shè)置一個(gè)游標(biāo),記錄循環(huán)的初始位置,下次循環(huán)直接從游標(biāo)記錄的位置開始循環(huán),然后滿足查找的條件就break,這樣既不破壞原來(lái)的數(shù)組,也能有效的減少循環(huán)的次數(shù)。

  let index = 0, sendList =[];
  function getMessage(time) {
    for(let i = 0, len = newList.length; i < len; i++) {
        const item = newList[i];
        // 這里的time如果不是1000、2000,而是1234、1214這種,就需要取一個(gè)浮動(dòng)范圍
        // 我這里就是簡(jiǎn)單用了定時(shí)器,所以比較簡(jiǎn)單
        if(item.time === time) {
          index = i;
          sendList.push(newList[i])
        } else if(sendList.length > 0) {
            // 這里的查詢結(jié)束條件為,對(duì)應(yīng)的時(shí)間范圍之外沒(méi)有消息了,并且需要發(fā)送的消息列表有消息,才break
        // 這里的結(jié)束條件想不到什么更好的方案了
        break;
    }
  }
}

上面我們只對(duì)視頻播放的時(shí)候做了優(yōu)化,如果下次用戶進(jìn)來(lái)進(jìn)度直接接近尾聲了,這時(shí)候首次查找尾部消息的時(shí)候,就需要把前面所有的消息都循環(huán)一遍,所以還需要繼續(xù)優(yōu)化。

二分查找

當(dāng)首次加載的時(shí)候,采用二分法查找到消息開始的位置,當(dāng)視頻播放的時(shí)候再根據(jù)查找到的index去循環(huán)消息體。

function binarySearch(arr, time) {
    let upperBound = arr.length - 1; // 記錄長(zhǎng)度
    let lowerBound = 0; // 記錄上次二分的位置
    let mid;
    // 切半分的位置 小于或等于 1就停止循環(huán)了
    while (lowerBound <= upperBound) {
      // (當(dāng)前總長(zhǎng)度 + 當(dāng)前中間點(diǎn)位置長(zhǎng)度) / 2 = 實(shí)際的中間點(diǎn)位置
      mid = Math.floor((upperBound + lowerBound) / 2);
      const item = arr[mid];
      const maxTime = time + 500;
      const minTime = time + 500;
      // 當(dāng)輸入的值大于中間值時(shí),向后移動(dòng)一位
      if (time > maxTime) {
        lowerBound = mid + 1;
      } else if (time < minTime) {
        // 當(dāng)輸入值小于中間值時(shí),向前移動(dòng)一位
        upperBound = mid - 1;
      } else {
        return mid; // 找到指定數(shù)據(jù)位置
      }
    }
    return -1;
  }
function findIndex(startPlayTime: number) {
    const searchIndex = binarySearch(this.messageList, time);
    // 賦值索引,用于快速發(fā)送消息
    if (searchIndex !== -1) {
      index = searchIndex;
    }
  }

完結(jié)

寫到這里本篇文章就不再會(huì)更新了,從最開始的splice方法,然后到后面的游標(biāo)法和二分法,做了逐漸的優(yōu)化。

這個(gè)也是在項(xiàng)目中每次迭代去做的優(yōu)化(前提是給你的排期你能有時(shí)間去做)。本文涉及的知識(shí)點(diǎn)可能并不是很重要,在這里我要跟大家說(shuō)的是,我們平時(shí)在寫代碼的時(shí)候,要善于發(fā)現(xiàn)代碼的可優(yōu)化空間,如果你發(fā)現(xiàn)了并且實(shí)事求是的去做了,你的能力就會(huì)有更大的提高,而且這個(gè)發(fā)現(xiàn)的過(guò)程你可以找同事,找leader去給你review代碼,在業(yè)務(wù)中沉淀出來(lái)的代碼比你自己平時(shí)寫個(gè)小demo寫的代碼更能讓你成長(zhǎng)。

更多關(guān)于JS前端數(shù)據(jù)循環(huán)優(yōu)化的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • JavaScript提取元素中第一個(gè)子元素的實(shí)現(xiàn)方法

    JavaScript提取元素中第一個(gè)子元素的實(shí)現(xiàn)方法

    本文主要介紹了JavaScript提取元素中第一個(gè)子元素的實(shí)現(xiàn)方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-06-06
  • javascript實(shí)現(xiàn)全角與半角字符的轉(zhuǎn)換

    javascript實(shí)現(xiàn)全角與半角字符的轉(zhuǎn)換

    這篇文章主要介紹了javascript實(shí)現(xiàn)全角與半角字符的轉(zhuǎn)換的相關(guān)代碼與知識(shí)點(diǎn)分享,需要的朋友可以參考下
    2015-01-01
  • Add a Table to a Word Document

    Add a Table to a Word Document

    Add a Table to a Word Document...
    2007-06-06
  • Bootstrap使用基礎(chǔ)教程詳解

    Bootstrap使用基礎(chǔ)教程詳解

    Bootstrap ——來(lái)自Twitter的流行前端框架。接下來(lái)通過(guò)本文給大家介紹bootstrap入門基礎(chǔ)腳本,包括bootstrap特征及使用方面的知識(shí)點(diǎn),感興趣的朋友一起看看吧
    2016-09-09
  • 原生js仿淘寶網(wǎng)商品放大鏡效果

    原生js仿淘寶網(wǎng)商品放大鏡效果

    本文主要介紹了原生js仿淘寶網(wǎng)商品放大鏡效果的實(shí)例,具有很好的參考價(jià)值,下面跟著小編一起來(lái)看下吧
    2017-02-02
  • layuimini框架實(shí)現(xiàn)點(diǎn)擊菜單欄回到起始頁(yè)的解決方案

    layuimini框架實(shí)現(xiàn)點(diǎn)擊菜單欄回到起始頁(yè)的解決方案

    這篇文章主要介紹了layuimini框架實(shí)現(xiàn)點(diǎn)擊菜單欄回到起始頁(yè)的解決方案,本文通過(guò)圖文示例代碼給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧
    2024-06-06
  • js+css實(shí)現(xiàn)打字效果

    js+css實(shí)現(xiàn)打字效果

    這篇文章主要為大家詳細(xì)介紹了js+css打字效果的實(shí)現(xiàn)方法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-04-04
  • 使用CoffeeScrip優(yōu)美方式編寫javascript代碼

    使用CoffeeScrip優(yōu)美方式編寫javascript代碼

    CoffeeScript就是JavaScript,他進(jìn)行的是一對(duì)一的編譯,或者說(shuō)是翻譯,而且編譯成的JavaScript代碼可讀性很強(qiáng)。本文給大家介紹使用CoffeeScript優(yōu)美方式編寫javascript代碼,感興趣的朋友一起看看吧
    2015-10-10
  • js+ajax實(shí)現(xiàn)獲取文件大小的方法

    js+ajax實(shí)現(xiàn)獲取文件大小的方法

    這篇文章主要介紹了js+ajax實(shí)現(xiàn)獲取文件大小的方法,涉及JavaScript調(diào)用ajax交互及后臺(tái)C#文件操作的相關(guān)技巧,需要的朋友可以參考下
    2015-12-12
  • 分享經(jīng)典的JavaScript開發(fā)技巧

    分享經(jīng)典的JavaScript開發(fā)技巧

    這篇文章向大家分享了40多個(gè)經(jīng)典的JavaScript開發(fā)技巧,相信讀完這篇文章對(duì)大家開發(fā)javascript有很大的幫助作用,感興趣的小伙伴們可以參考一下
    2015-11-11

最新評(píng)論

阿克苏市| 兰溪市| 云林县| 昂仁县| 永定县| 偃师市| 郯城县| 湘阴县| 鸡西市| 榆社县| 栾城县| 安西县| 四会市| 涟水县| 霍城县| 金沙县| 尤溪县| 灵武市| 湖北省| 海淀区| 柞水县| 安西县| 于都县| 稻城县| 峡江县| 罗甸县| 曲沃县| 方城县| 庄浪县| 博客| 烟台市| 福贡县| 苏州市| 通海县| 岢岚县| 安吉县| 年辖:市辖区| 新沂市| 邵阳县| 香格里拉县| 汝州市|