成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

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

Nekron / 3373人閱讀

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

拜年

新年伊始,本搬磚汪先給各位老爺們拜個晚年,祝各位技術(shù)大牛們在新的一年代碼功底更進一步,家庭幸福美滿!

需求

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

第一版
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("開始時間:" + 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í)行時間
    j++
  }

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

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

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

loop()

結(jié)果如下:


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

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

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

結(jié)果如下:


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

第三版

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

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("開始時間:" + startTime) // 打印開始時間

function loop() {
  count++
  var offset = new Date().getTime() - (startTime + count * interval); // 代碼執(zhí)行所消耗的時間
  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)所消耗的時間

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

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

setTimeout(loop, currentInterval)

結(jié)果如下:


暫時性結(jié)論

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

setInterval > 修正時間間隔的遞歸setTimeout > 遞歸setTimeout

疑問

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

業(yè)務(wù)場景中實現(xiàn)倒計時的標準做法?

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

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

參考資料

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

原文

歡迎訪問我的博客

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

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/93219.html

相關(guān)文章

  • JS 異步實現(xiàn)

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

    sihai 評論0 收藏0
  • 瀏覽器渲染機制

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

    appetizerio 評論0 收藏0
  • 瀏覽器渲染機制

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

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

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

    darry 評論0 收藏0
  • 瀏覽器知識

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

    Pluser 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<