欧美一区二区三区老妇人-欧美做爰猛烈大尺度电-99久久夜色精品国产亚洲a-亚洲福利视频一区二区

setTimeout()與setInterval()的源碼分析

最近筆者在開(kāi)發(fā)的過(guò)程中,因?yàn)樾枰獙?duì)頁(yè)面進(jìn)行動(dòng)態(tài)渲染,又不想一直刷新頁(yè)面數(shù)據(jù),而是讓瀏覽器根據(jù)客戶需要?jiǎng)討B(tài)對(duì)渲染數(shù)據(jù),這個(gè)時(shí)候就用到了setInterval這個(gè)函數(shù),可是這個(gè)函數(shù)和setTimeout()相比又有什么區(qū)別呢?我們知道:

網(wǎng)站設(shè)計(jì)制作、成都網(wǎng)站建設(shè)的開(kāi)發(fā),更需要了解用戶,從用戶角度來(lái)建設(shè)網(wǎng)站,獲得較好的用戶體驗(yàn)。創(chuàng)新互聯(lián)建站多年互聯(lián)網(wǎng)經(jīng)驗(yàn),見(jiàn)的多,溝通容易、能幫助客戶提出的運(yùn)營(yíng)建議。作為成都一家網(wǎng)絡(luò)公司,打造的就是網(wǎng)站建設(shè)產(chǎn)品直銷的概念。選擇創(chuàng)新互聯(lián)建站,不只是建站,我們把建站作為產(chǎn)品,不斷的更新、完善,讓每位來(lái)訪用戶感受到浩方產(chǎn)品的價(jià)值服務(wù)。

  • setTimeout()是綁定在瀏覽器window的一個(gè)方法,可以通過(guò)這個(gè)方法指定一段代碼或者函數(shù)在多少毫秒(ms)后執(zhí)行,并返回該定時(shí)器的編號(hào),當(dāng)然了我們可以通過(guò)clearTimeout()取消代碼的執(zhí)行
  • setInterval()綁定在瀏覽器window的一個(gè)方法,可以通過(guò)setInterval指定一段代碼或函數(shù)定時(shí)在多少毫秒(ms)后執(zhí)行,并傳回該定時(shí)器的編號(hào),當(dāng)然了我們可以通過(guò)clearInterval()取消代碼的執(zhí)行
    最有效且直接的就是做個(gè)小實(shí)驗(yàn)感受下:

setInterval()執(zhí)行方法其實(shí)是將需執(zhí)行的代碼加入到任務(wù)隊(duì)列,直到輪到代碼執(zhí)行時(shí),確定時(shí)間是否已經(jīng)到了,若到達(dá)則執(zhí)行代碼

var startTime=new Date();
var func = function(){
console.log('start: ' + (new Date()-startTime));
for(var i=0; i<1000000000; i++){}
console.log('end: ' + (new Date()-startTime));
};
setInterval(func,1000);

上面這段代碼的執(zhí)行之后,你會(huì)發(fā)現(xiàn)setInterval的end與start時(shí)間跳動(dòng)非常大,并不是我們?cè)O(shè)置的1000ms。由于setInterval是一開(kāi)始就標(biāo)定了執(zhí)行的時(shí)間點(diǎn),當(dāng)所注冊(cè)的函數(shù)(func)超過(guò),因此不會(huì)是固定的1000ms。
setTimeout() 與 setInterval() 的源碼分析
setTimeout()的用法大致與setInterval相同,不同的在于定時(shí)執(zhí)行,我們同樣來(lái)測(cè)試延遲執(zhí)行的現(xiàn)象

var startTime=new Date();
var func = function(){
console.log('start: ' + (new Date()-startTime));
for(var i=0; i<1000000000; i++){};
console.log('end: ' + (new Date()-startTime));
setTimeout(func,1000);
};
setTimeout(func,1000);

觀察下圖可以發(fā)現(xiàn) setTimeout 所設(shè)置的時(shí)間間隔,會(huì)因?yàn)槟壳叭蝿?wù)隊(duì)列所執(zhí)行的代碼而可能發(fā)生延誤執(zhí)行的情況,我們可以發(fā)現(xiàn)上面這段代碼,執(zhí)行func的end與start時(shí)間間隔基本上是符合我們所設(shè)定的1000ms
setTimeout() 與 setInterval() 的源碼分析
透過(guò)現(xiàn)象看本質(zhì),我們不妨看下這兩個(gè)函數(shù)的源碼
setTimeout() 與 setInterval() 的源碼分析
從函數(shù)聲明可以知道setInterval這里允許傳參,允許我們傳入一個(gè)方法,讓其在一定時(shí)間(number)后執(zhí)行,其時(shí)間等待依賴于調(diào)度器_scheduler,而方法的執(zhí)行是由_fnAndFlush來(lái)負(fù)責(zé)調(diào)控的,不過(guò)由于有_requeuePeriodicTimer這個(gè)方法的存在使得時(shí)間間隔不是我們所設(shè)固定1000ms

....
case 'setInterval':
  task.data!['handleId'] = this._setInterval(
      task.invoke, task.data!['delay']!,
      Array.prototype.slice.call((task.data as any)['args'], 2));
  break; 
....

private _setInterval(fn: Function, interval: number, args: any[]): number {
  let id = Scheduler.nextId;
  let completers = {onSuccess: null as any, onError: this._dequeuePeriodicTimer(id)};
  let cb = this._fnAndFlush(fn, completers);

  // Use the callback created above to requeue on success.
  completers.onSuccess = this._requeuePeriodicTimer(cb, interval, args, id);

  // Queue the callback and dequeue the periodic timer only on error.
  this._scheduler.scheduleFunction(cb, interval, args, true);
  this.pendingPeriodicTimers.push(id);
  return id;
}  

先來(lái)看下_fnAndFlush的代碼,這個(gè)函數(shù)其實(shí)是將我們的所需要執(zhí)行的函數(shù)刷入內(nèi)存中,等待瀏覽器的執(zhí)行

private _fnAndFlush(fn: Function, completers: {onSuccess?: Function, onError?: Function}):
    Function {
  return (...args: any[]): boolean => {
    fn.apply(global, args);

    if (this._lastError === null) {  // Success
      if (completers.onSuccess != null) {
        completers.onSuccess.apply(global);
      }
      // Flush microtasks only on success.
      this.flushMicrotasks();
    } else {  // Failure
      if (completers.onError != null) {
        completers.onError.apply(global);
      }
    }
    // Return true if there were no errors, false otherwise.
    return this._lastError === null;
  };
}

我們不妨來(lái)看下_requeuePeriodicTimer這個(gè)方法所完成的功能的特點(diǎn)。其會(huì)將瀏覽器內(nèi)存中存在的函數(shù)加入隊(duì)列中執(zhí)行(如果存在的話),函數(shù)功能完成過(guò)程中已經(jīng)進(jìn)入下個(gè)scheduler的執(zhí)行周期,即函數(shù)在執(zhí)行過(guò)程中還有一個(gè)計(jì)時(shí)器在等待下個(gè)函數(shù)的執(zhí)行。正如實(shí)驗(yàn)中,我們觀察到的所有的start間隔大致是1000ms

private _requeuePeriodicTimer(fn: Function, interval: number, args: any[], id: number): Function {
  return () => {
    // Requeue the timer callback if it's not been canceled.
    if (this.pendingPeriodicTimers.indexOf(id) !== -1) {
      this._scheduler.scheduleFunction(fn, interval, args, true, false, id);
    }
  };
}

對(duì)于setTimeout這里允許傳參,允許我們傳入一個(gè)方法,讓其在一定時(shí)間(number)后執(zhí)行,其時(shí)間等待依賴于調(diào)度器_scheduler,而調(diào)度器正是讓我們的函數(shù)時(shí)間間隔符合我們?cè)O(shè)置的1000ms的原因,而方法的執(zhí)行則是由_fnAndFlush來(lái)負(fù)責(zé)調(diào)控的,因?yàn)閟etTimeout并不會(huì)將執(zhí)行函數(shù)推入隊(duì)列中,因此計(jì)時(shí)器不會(huì)運(yùn)行直到前一個(gè)周期的函數(shù)都執(zhí)行完畢之后才開(kāi)始進(jìn)入下一個(gè)周期,正如實(shí)驗(yàn)代碼中所寫(xiě)的等待1000ms

...
case 'setTimeout':
  task.data!['handleId'] = this._setTimeout(
      task.invoke, task.data!['delay']!,
      Array.prototype.slice.call((task.data as any)['args'], 2));
  break;
...
private _setTimeout(fn: Function, delay: number, args: any[], isTimer = true): number {
  let removeTimerFn = this._dequeueTimer(Scheduler.nextId);
  // Queue the callback and dequeue the timer on success and error.
  let cb = this._fnAndFlush(fn, {onSuccess: removeTimerFn, onError: removeTimerFn});
  let id = this._scheduler.scheduleFunction(cb, delay, args, false, !isTimer);
  if (isTimer) {
    this.pendingTimers.push(id);
  }
  return id;
}   

參考資料:
https://www.jeffjade.com/2016/01/10/2016-01-10-javacript-setTimeout/
https://www.jeffjade.com/2016/01/10/2016-01-10-javaScript-setInterval/

分享題目:setTimeout()與setInterval()的源碼分析
轉(zhuǎn)載來(lái)源:http://chinadenli.net/article28/jhpocp.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供手機(jī)網(wǎng)站建設(shè)電子商務(wù)網(wǎng)站排名定制開(kāi)發(fā)虛擬主機(jī)網(wǎng)站設(shè)計(jì)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

網(wǎng)站托管運(yùn)營(yíng)