成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專欄INFORMATION COLUMN

從倒計(jì)時(shí)的實(shí)現(xiàn)深入探究setTimout與setInterval

Nekron / 3390人閱讀

摘要:這么執(zhí)行導(dǎo)致的結(jié)果是每次的時(shí)間必然會(huì)大于主線程代碼執(zhí)行消耗的時(shí)間,而當(dāng)這個(gè)主線程代碼執(zhí)行消耗的時(shí)間累加起來超過時(shí),就會(huì)出現(xiàn)跳一秒的情況。

拜年

新年伊始,本搬磚汪先給各位老爺們拜個(gè)晚年,祝各位技術(shù)大牛們?cè)谛碌囊荒甏a功底更進(jìn)一步,家庭幸福美滿!

需求

下面進(jìn)入正題:在翻閱segmentfault社區(qū)時(shí)看到某巨廠面試要求實(shí)現(xiàn)一個(gè)倒計(jì)時(shí)功能,之前也沒有仔細(xì)實(shí)現(xiàn)過,趁年初來任務(wù)還沒來得及分配,趕緊著手實(shí)現(xiàn)了一個(gè)。

第一版
var period = 60*1000*60*2
var end = new Date().getTime() + period
var date = new Date(end)
var interval = 1000
var count = 0
var startTime = new Date().getTime()

console.log("開始時(shí)間:" + startTime)

function loopInner() {
  count++

  var diff = end - new Date().getTime()
  var h = Math.floor(diff / (60*1000*60))
  var hdiff = diff % (60*1000*60)
  var m = Math.floor(hdiff / (60*1000))
  var mdiff = hdiff % (60*1000)
  var s = mdiff / 1000
  var sCeil = Math.ceil(s)

  var j = 0
  while (j<100000000) { // 放大主線程代碼執(zhí)行時(shí)間
    j++
  }

  console.log(h + "小時(shí)", m + "分鐘:", s + "秒(精確到毫秒)", sCeil + "秒(進(jìn)一法)")
}

function loop() {
  loopInner() // 首先var j = 0

  if (count === 100) {
    var endTime = new Date().getTime()
    console.log("結(jié)束時(shí)間:" + endTime) // 打印開始時(shí)間
    console.log("時(shí)間差毫秒數(shù):" + Number(endTime - startTime) + "對(duì)應(yīng)秒數(shù):" + Number(endTime - startTime) / 1000)
    console.log("計(jì)時(shí)器計(jì)算秒數(shù):100")
  } else {
    return setTimeout(loop, interval)
  }
}

loop()

結(jié)果如下:


第一版實(shí)現(xiàn)我使用的是遞歸的setTimeout方法,原因是之前曾經(jīng)看到過遞歸的setTimeout能避免setInterval忽視代碼執(zhí)行時(shí)間,而一個(gè)事件隊(duì)列里只會(huì)有一個(gè)setInterval事件導(dǎo)致的部分setInterval事件被忽略的情況。這么執(zhí)行導(dǎo)致的結(jié)果是每次setTimeout的時(shí)間必然會(huì)大于1000ms(1000 + 主線程代碼執(zhí)行消耗的時(shí)間),而當(dāng)這個(gè)主線程代碼執(zhí)行消耗的時(shí)間累加起來超過1s時(shí),就會(huì)出現(xiàn)跳一秒的情況。這一版實(shí)現(xiàn)方案的結(jié)果不盡如人意。

第二版
var period = 60 * 1000 * 60 * 2
var end
var date = new Date(end)
var interval = 1000
var count = 0
var startTime = new Date().getTime()

console.log("開始時(shí)間:" + startTime)

var loop = function () {
  count++
  if (count === 100) {
    var endTime = new Date().getTime()
    console.log("結(jié)束時(shí)間:" + endTime) // 打印開始時(shí)間
    console.log("時(shí)間差毫秒數(shù):" + Number(endTime - startTime) + "對(duì)應(yīng)秒數(shù):" + Number(endTime - startTime) / 1000)
    console.log("計(jì)時(shí)器計(jì)算秒數(shù):100")
    return clearInterval(Itvid)
  }

  if (!end) { end = new Date().getTime() + period }
  var diff = end - new Date().getTime()
  var h = Math.floor(diff / (60 * 1000 * 60))
  var hdiff = diff % (60 * 1000 * 60)
  var m = Math.floor(hdiff / (60 * 1000))
  var mdiff = hdiff % (60 * 1000)
  var s = mdiff / (1000)
  var roundS = Math.round(s)

  var j = 0
  while (j<100000000) { // 放大主線程代碼執(zhí)行時(shí)間
    j++
  }

  console.log(h + "小時(shí):", m + "分鐘:", s + "秒(精確到毫秒)", roundS + "秒(四舍五入)")
}
var Itvid = setInterval(loop, interval)

結(jié)果如下:


這一版的結(jié)果比較接近正確答案,利用setInterval不等待執(zhí)行代碼完成就直接加入隊(duì)列的特性(參考setInterval與setTimeout的精確度問題),再加上用Math.round方法修正js的異步方法所造成的幾毫秒的誤差即可。而setInterval畢竟也是瀏覽器的api,同樣是有幾毫秒的差異的。

第三版

這一版是我選擇在第一種寫法的基礎(chǔ)上做改良:每次循環(huán)中基于此次代碼執(zhí)行所消耗的時(shí)間對(duì)下次循環(huán)所消耗的時(shí)間間隔做修正。

var period = 60 * 1000 * 60 * 2
var startTime = new Date().getTime();
var count = 0
var end = new Date().getTime() + period
var interval = 1000
var currentInterval = interval

console.log("開始時(shí)間:" + startTime) // 打印開始時(shí)間

function loop() {
  count++
  var offset = new Date().getTime() - (startTime + count * interval); // 代碼執(zhí)行所消耗的時(shí)間
  var diff = end - new Date().getTime()
  var h = Math.floor(diff / (60 * 1000 * 60))
  var hdiff = diff % (60 * 1000 * 60)
  var m = Math.floor(hdiff / (60 * 1000))
  var mdiff = hdiff % (60 * 1000)
  var s = mdiff / (1000)
  var sCeil = Math.ceil(s)
  var sFloor = Math.floor(s)
  currentInterval = interval - offset // 得到下一次循環(huán)所消耗的時(shí)間

  var j = 0
  while (j<100000000) { // 放大主線程代碼執(zhí)行時(shí)間
    j++
  }

  console.log("時(shí):"+h, "分:"+m, "毫秒:"+s, "秒向上取整:"+sCeil, "代碼執(zhí)行時(shí)間:"+offset+"ms", "下次循環(huán)間隔"+currentInterval+"ms") // 打印 時(shí) 分 秒 代碼執(zhí)行時(shí)間 下次循環(huán)間隔
  if (count === 100) {
    var endTime = new Date().getTime()
    console.log("結(jié)束時(shí)間:" + endTime) // 打印開始時(shí)間
    console.log("時(shí)間差毫秒數(shù):" + Number(endTime - startTime) + "對(duì)應(yīng)秒數(shù):" + Number(endTime - startTime) / 1000)
    console.log("計(jì)時(shí)器計(jì)算秒數(shù):100")
  } else {
    setTimeout(loop, currentInterval)
  }
}

setTimeout(loop, currentInterval)

結(jié)果如下:


暫時(shí)性結(jié)論

對(duì)于同步代碼執(zhí)行耗時(shí)不是過大(幾十毫秒到幾百毫秒之間)的情況,通過實(shí)驗(yàn)得到結(jié)果:

setInterval > 修正時(shí)間間隔的遞歸setTimeout > 遞歸setTimeout

疑問

業(yè)務(wù)場(chǎng)景中是否存在同步代碼執(zhí)行時(shí)間超過數(shù)秒的情況?

業(yè)務(wù)場(chǎng)景中實(shí)現(xiàn)倒計(jì)時(shí)的標(biāo)準(zhǔn)做法?

從服務(wù)端端獲取開始時(shí)間會(huì)有時(shí)間損耗(http傳輸?shù)暮臅r(shí)),這個(gè)耗時(shí)有沒有方法規(guī)避?

依然遺留這些問題存在,還請(qǐng)各位不吝賜教。

參考資料

JS實(shí)現(xiàn)活動(dòng)精確倒計(jì)時(shí)
w3.org
javascript線程解釋(setTimeout,setInterval你不知道的事)

原文

歡迎訪問我的博客

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/93219.html

相關(guān)文章

  • JS 異步實(shí)現(xiàn)

    摘要:由于引擎同一時(shí)間只執(zhí)行一段代碼這是由單線程的性質(zhì)決定的,所以每個(gè)代碼塊阻塞了其它異步事件的進(jìn)行。這意味著瀏覽器將等待著一個(gè)新的異步事件發(fā)生。異步的任務(wù)執(zhí)行的順序是不固定的,主要看返回的速度。 我們經(jīng)常說JS是單線程的,比如node.js研討會(huì)上大家都說JS的特色之一是單線程的,這樣使JS更簡單明了,可是大家真的理解所謂JS的單線程機(jī)制嗎?單線程時(shí),基于事件的異步機(jī)制又該當(dāng)如何,這些知識(shí)...

    sihai 評(píng)論0 收藏0
  • 瀏覽器渲染機(jī)制

    摘要:瀏覽器渲染進(jìn)程瀏覽器內(nèi)核進(jìn)程,內(nèi)部是多線程的默認(rèn)每個(gè)頁面一個(gè)進(jìn)程,互不影響。事件觸發(fā)線程歸屬于瀏覽器而不是引擎,用來控制事件循環(huán)可以理解成引擎自己都忙不過來,需要瀏覽器另開線程協(xié)助。 線程和進(jìn)程 進(jìn)程和線程的概念可以這樣理解: 進(jìn)程是一個(gè)工廠,工廠有它的獨(dú)立資源--工廠之間相互獨(dú)立--線程是工廠中的工人,多個(gè)工人協(xié)作完成任務(wù)--工廠內(nèi)有一個(gè)或多個(gè)工人--工人之間共享空間 工廠有多個(gè)工人...

    appetizerio 評(píng)論0 收藏0
  • 瀏覽器渲染機(jī)制

    摘要:瀏覽器渲染進(jìn)程瀏覽器內(nèi)核進(jìn)程,內(nèi)部是多線程的默認(rèn)每個(gè)頁面一個(gè)進(jìn)程,互不影響。事件觸發(fā)線程歸屬于瀏覽器而不是引擎,用來控制事件循環(huán)可以理解成引擎自己都忙不過來,需要瀏覽器另開線程協(xié)助。 線程和進(jìn)程 進(jìn)程和線程的概念可以這樣理解: 進(jìn)程是一個(gè)工廠,工廠有它的獨(dú)立資源--工廠之間相互獨(dú)立--線程是工廠中的工人,多個(gè)工人協(xié)作完成任務(wù)--工廠內(nèi)有一個(gè)或多個(gè)工人--工人之間共享空間 工廠有多個(gè)工人...

    lncwwn 評(píng)論0 收藏0
  • HTML執(zhí)行順序-一探究

    摘要:而進(jìn)程是多線程的,它主要包含以下主要線程渲染線程負(fù)責(zé)渲染瀏覽器界面,解析,,構(gòu)建樹和樹,布局和繪制等。且加載解析執(zhí)行會(huì)阻止解析器往下執(zhí)行,要強(qiáng)調(diào)渲染和下載是不沖突的,渲染是線程在執(zhí)行,下載是下載線程在執(zhí)行,瀏覽器多線程。 了解瀏覽器線程基礎(chǔ) 一個(gè)頁面的呈現(xiàn)主要是由瀏覽器渲染進(jìn)程實(shí)現(xiàn)的(render進(jìn)程),主要作用為頁面的渲染,腳本執(zhí)行,事件處理等。而render進(jìn)程是多線程的,它主要包...

    darry 評(píng)論0 收藏0
  • 瀏覽器知識(shí)

    摘要:瀏覽器的渲染進(jìn)程是多線程的。異步請(qǐng)求線程在在連接后是通過瀏覽器新開一個(gè)線程請(qǐng)求將檢測(cè)到狀態(tài)變更時(shí),如果設(shè)置有回調(diào)函數(shù),異步線程就產(chǎn)生狀態(tài)變更事件,將這個(gè)回調(diào)再放入事件隊(duì)列中。 [TOC] 瀏覽器進(jìn)程線程 區(qū)分線程和進(jìn)程 **- 什么是進(jìn)程** 狹義定義:進(jìn)程是正在運(yùn)行的程序的實(shí)例(an instance of a computer program that is being exe...

    Pluser 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<