国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

從倒計時的實現深入探究setTimout與setInterval

Nekron / 3352人閱讀

摘要:這么執行導致的結果是每次的時間必然會大于主線程代碼執行消耗的時間,而當這個主線程代碼執行消耗的時間累加起來超過時,就會出現跳一秒的情況。

拜年

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

需求

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

第一版
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) { // 放大主線程代碼執行時間
    j++
  }

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

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

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

loop()

結果如下:


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

第二版
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("結束時間:" + endTime) // 打印開始時間
    console.log("時間差毫秒數:" + Number(endTime - startTime) + "對應秒數:" + Number(endTime - startTime) / 1000)
    console.log("計時器計算秒數: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) { // 放大主線程代碼執行時間
    j++
  }

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

結果如下:


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

第三版

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

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); // 代碼執行所消耗的時間
  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 // 得到下一次循環所消耗的時間

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

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

setTimeout(loop, currentInterval)

結果如下:


暫時性結論

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

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

疑問

業務場景中是否存在同步代碼執行時間超過數秒的情況?

業務場景中實現倒計時的標準做法?

從服務端端獲取開始時間會有時間損耗(http傳輸的耗時),這個耗時有沒有方法規避?

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

參考資料

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

原文

歡迎訪問我的博客

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/93219.html

相關文章

  • JS 異步實現

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

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

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

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

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

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

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

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

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

    Pluser 評論0 收藏0

發表評論

0條評論

Nekron

|高級講師

TA的文章

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