真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯網站制作重慶分公司

關于javascript計時器的案例分析-創(chuàng)新互聯

這篇文章給大家分享的是有關關于javascript計時器的案例分析的內容。小編覺得挺實用的,因此分享給大家做個參考。一起跟隨小編過來看看吧。

虹口網站建設公司創(chuàng)新互聯建站,虹口網站設計制作,有大型網站制作公司豐富經驗。已為虹口數千家提供企業(yè)網站建設服務。企業(yè)網站搭建\成都外貿網站建設要多少錢,請找那個售后服務好的虹口做網站的公司定做!

先從一個面試題開始:

JavaScript 面試題:

setTimeout 和 setInterval 的源代碼是在哪里實現的? (不能百度和谷歌 )

在繼續(xù)往下看之前,請先在你的頭腦中回答問題


你的答案可能會是 V8(或其他VM),但很遺憾,這是錯的。盡管 “JavaScript Timers” 的應用很廣泛,但是 setTimeoutsetInterval 之類的函數并不是 ECMAScript 規(guī)范或任何一種 JavaScript 引擎實現的一部分。Timer 函數是由瀏覽器實現的,不同瀏覽器的實現方式會有所不同。同時 Timer 也是由 Node.js 運行時本身實現的。

在瀏覽器中,主要的計時器函數是 Window 接口的一部分,這個接口還有一些其他函數和對象。該接口使其所有元素在主 JavaScript 作用域內全局可用。這就是為什么你可以直接在瀏覽器的控制臺中執(zhí)行 setTimeout 的原因。

在 Node 中,計時器是 global 對象的一部分,該對象的行為類似于瀏覽器的 window 。你可以在 Node 的源代碼中找到它的實現。

有些人可能認為這個面試題不咋樣,但是我認為你應該了解這個,因為如果你不了解這一點,則可能表明你并不完全了解 V8(及其他VM)是如何與瀏覽器和 Node 交互的。

以下是一些關于計時器函數的例子和編碼挑戰(zhàn)的練習:

延遲函數的執(zhí)行

定時器函數是高階函數,可用于延遲或重復其他函數的執(zhí)行(它們作為第一個參數)。

以下是延遲執(zhí)行的例子:

// example1.js

setTimeout(
  () => {
    console.log('Hello after 4 seconds');
  },
  4 * 1000
);

本例用 setTimeoutconsole.log 的輸出延遲4秒。 setTimeout 的第二個參數是延遲時間(以毫秒為單位)。這就是為什么要用 4 乘以 1000 的原因。

setTimeout 的第一個參數是你想要延遲執(zhí)行的函數。

如果用 node 命令執(zhí)行 example1.js 文件,Node 會暫停 4。秒鐘,然后輸出一行消息,之后退出。

注意,setTimeout 的第一個參數只是一個函數引用。也可以不像 example1.js 那樣使用內聯函數。下面是不用內聯函數的相同功能的代碼:

const func = () => {
  console.log('Hello after 4 seconds');
};

setTimeout(func, 4 * 1000);

傳遞參數

如果要讓用 setTimeout 延遲執(zhí)行的函數接受參數,可以將 setTimeout 本身其余的參數用于將參數值傳遞給所延遲的函數。

// 函數: func(arg1, arg2, arg3, ...)
// 可以用: setTimeout(func, delay, arg1, arg2, arg3, ...)

這是一個例子:

// example2.js

const rocks = who => {
  console.log(who + ' rocks');
};

setTimeout(rocks, 2 * 1000, 'Node.js');

上面的 rocks 函數延遲了 2 秒,它接受參數 who,而 setTimeout 調用將值 “Node.js” 用于 who 參數。

node 命令執(zhí)行 example2.js 將會在 2 秒鐘后打印出 “Node.js rocks”。

計時器編碼挑戰(zhàn) #1

現在用你在前面所學到的關于 setTimeout 的知識,在要求的延遲時間后輸出以下 2 條內容。

  • 4 秒鐘后輸出 “Hello after 4 seconds
  • 8 秒鐘后輸出 “Hello after 8 seconds”。

要求

你只能定義一個函數,這其中包括內聯函數。這意味著你所有的 setTimeout 調用將必須使用完全相同的函數。

解決方案

這是我的方法:

// solution1.js

const theOneFunc = delay => {
  console.log('Hello after ' + delay + ' seconds');
};

setTimeout(theOneFunc, 4 * 1000, 4);
setTimeout(theOneFunc, 8 * 1000, 8);

我已經使 theOneFunc 接收了一個 delay 參數,并在輸出的消息中使用了 delay 參數的值。這樣該函數可以根據傳遞給它的延遲值來輸出不同的消息。

然后,我在兩個 setTimeout 調用中使用了 theOneFunc,一個在 4 秒后觸發(fā),另一個在 8 秒后觸發(fā)。這兩個setTimeout 調用都用到了第三個參數來表示 theOneFuncdelay 參數。

最后用 node 命令執(zhí)行 solution1.js 文件,第一條消息輸出在 4 秒鐘后,第二條消息在 8 秒鐘后。

重復執(zhí)行一個函數

如果要求你一直每隔 4 秒鐘輸出一條消息怎么辦?

盡管你可以將 setTimeout 放入循環(huán)中,但是計時器 API也提供了 setInterval 函數,這能夠滿足一直做某件事的要求。

下面是 setInterval 的例子:

// example3.js

setInterval(
  () => console.log('Hello every 3 seconds'),
  3000
);

本例將會每 3 秒輸出一次消息。用 node 命令執(zhí)行 example3.js 將會使 Node 一直輸出這個消息,直到你用  CTRL + C 終止進程為止。

取消計時器

因為調用計時器函數會實現計劃一個動作,所以該動作也可以在執(zhí)行之前取消。

調用 setTimeout 會返回一個計時器 ID,可以把計時器 ID 當做參數傳給 clearTimeout 函數來取消它。下面一個例子:

// example4.js

const timerId = setTimeout(
  () => console.log('你看不到這行輸出!'),
  0
);

clearTimeout(timerId);

這個簡單的計時器應該在 0 毫秒后被觸發(fā)(使其立即生效),但實際上并不會,因為此時我們正在獲取  timerId 值,并在調用 clearTimeout 之后立即將其取消。

node 命令執(zhí)行 example4.js 時,Node 不會輸出任何內容,而程序將會退出。

順便說一句,在 Node.js 中,還有另一種方法對 0 ms 進行 setTimeout 。 Node.js 計時器 API 還有一個名為 setImmediate 的函數,它與前面 0 毫秒的 setTimeout 基本上相同,但是不用指定延遲時間:

setImmediate(
  () => console.log('我等效于 0 毫秒的 setTimeout'),
);

setImmediate 函數并非在所有瀏覽器中都可用。千萬不要用在前端代碼中。

clearTimeout 類似,還有一個 clearInterval 函數,除了對 setInerval 的調用外,它們的功能相同,而且也有 clearImmediate 的調用。

定時器延遲是不能夠完全保證的

在上一個例子中,你可能注意到了,如果用 setTimeout0 毫秒之后執(zhí)行某個操作,并不意味著會馬上執(zhí)行它(在 setTimeout 這一行之后),而是在腳本中的所有其他內容( clearTimeout 這一行)之后才會執(zhí)行它的調用。

// example5.js

setTimeout(
  () => console.log('Hello after 0.5 seconds. MAYBE!'),
  500,
);

for (let i = 0; i < 1e10; i++) {
  // 同步阻塞
}

在這個例子中定義了計時器之后,我們立即通過一個大的 for 循環(huán)來阻塞運行。 1e10 的意思是 1 前面有 10 個零,所以這個循環(huán)是 100 億次循環(huán)(基本上模擬了繁忙的 CPU)。在循環(huán)時 Node 無法執(zhí)行任何操作。

當然,這在實際開發(fā)中非常糟糕,但是它能幫你了解 setTimeout 延遲是無法保證馬上就開始的事實。 500 ms 表示最小延遲為 500 ms。實際上,這段腳本將會執(zhí)行很長的時間。它必須先等待阻塞循環(huán)才能開始。

計時器編碼挑戰(zhàn) #2

編寫一段腳本,每秒輸出一次消息 “Hello World”,但僅輸出 5 次。 5 次后,腳本應輸出消息 “Done” 并退出。

要求:不能用 setTimeout

提示:你需要一個計數器。

解決方案

這是我的方法:

let counter = 0;
const intervalId = setInterval(() => {
  console.log('Hello World');
  counter += 1;if (counter === 5) {
    console.log('Done');
    clearInterval(intervalId);
  }
}, 1000);

counter 的值初始化為 0,然后通過 setInterval 得到其 ID。

延遲函數將輸出消息并使計數器加 1。在函數內部的 if 語句中檢查現在是否已經輸出 5 次了,如果是的話,則輸出“Done”并用 intervalId 常數清理。間隔延遲為 1000 毫秒。

究竟是誰調用了延遲函數?

當在常規(guī)函數中使用 JavaScript 的 this 關鍵字時,如下所示:

function whoCalledMe() {
  console.log('Caller is', this);
}

在關鍵字  this  中的值將代表函數的調用者。如果你在 Node REPL 內定義以上函數,則調用方將是 global 對象。如果在瀏覽器的控制臺中定義函數,則調用方將是 window 對象。

下面把函數定義為對象的屬性,這樣可以看的更加清楚:

const obj = { 
  id: '42',
  whoCalledMe() {
    console.log('Caller is', this);
  }
}; // 現在,函數引用為:obj.whoCallMe

現在,當你直接用其引用去調用 obj.whoCallMe 函數時,調用者將是 obj 對象(由其 ID 進行標識):

關于javascript計時器的案例分析

現在的問題是,如果把 obj.whoCallMe 的引用傳遞給 setTimetout 調用,調用者將會是誰?

// 將會輸出什么?
setTimeout(obj.whoCalledMe, 0);

在這種情況下,調用者會是誰?

根據執(zhí)行計時器函數的位置不同,答案也不一樣。在當前這種情況下,根本無法確定調用者是誰。你會失去對調用者的控制,因為計時器只是其中的一種可能。如果你在 Node REPL 中對其進行測試,則會看到調用者是一個 Timetout 對象:

關于javascript計時器的案例分析

注意,在常規(guī)函數中使用 JavaScript 的 this 關鍵字時這非常重要。如果你使用箭頭函數的話,則無需擔心調用者是誰。

計時器編碼挑戰(zhàn) #3

編寫一段腳本,連續(xù)輸出消息 “Hello World”,但是每次延遲都不一致。從 1 秒開始,然后每次增加 1 秒。即第二次會有 2 秒的延遲,第三時間會有3秒的延遲,依此類推。

如果在輸出的消息中包含延遲。預期的輸出如下:

Hello World. 1
Hello World. 2
Hello World. 3
...

要求: 你只能用 const 來定義變量,不能用 letvar

解決方案

由于延遲量是這項挑戰(zhàn)中的變量,因此在這里不能用 setInterval,但是可以在遞歸調用中使用 setTimeout 手動創(chuàng)建執(zhí)行間隔。第一個使用 setTimeout 執(zhí)行的函數將會創(chuàng)建另一個計時器,依此類推。

另外,因為不能用 letvar,所以我們沒有辦法用計數器來增加每次遞歸調用中的延遲,但是可以使遞歸函數的參數在遞歸調用中遞增。

下面的方法供你參考:

const greeting = delay =>
  setTimeout(() => {
    console.log('Hello World. ' + delay);
    greeting(delay + 1);
  }, delay * 1000);
greeting(1);

計時器編碼挑戰(zhàn) #4

編寫一段腳本,用和挑戰(zhàn)#3 相同的可變延遲概念連續(xù)輸出消息 “Hello World”,但是這次,每個主延遲間隔以 5 條消息為一組。前 5 條消息的延遲為 100ms,然后是下 5 條消息的延遲為 200ms,然后是 300ms,依此類推。

腳本的行為如下:

  • 在 100 毫秒時,腳本開始輸出 “Hello World”,并以 100 毫秒的間隔執(zhí)行 5 次。第一條消息將在 100 毫秒顯示,第二條消息在 200 毫秒出現,依此類推。
  • 在輸出前 5。條消息之后,腳本應將主延遲增加到 200ms。所以第 6 條消息將在 500 ms + 200 ms(700ms)時輸出,第 7 條消息將在 900ms 輸出,第 8。條消息將在 1100ms 輸出,依此類推。
  • 10 條消息后,腳本把主延遲增加到 300ms。所以第 11 條消息應該在 500ms + 1000ms + 300ms(18000ms)時輸出。第 12 條消息在 21000ms 輸出,依此類推。
  • 一直延續(xù)這個模式。

在輸出的消息中包含延遲。預期的輸出如下所示(不帶注釋):

Hello World. 100  // At 100ms
Hello World. 100  // At 200ms
Hello World. 100  // At 300ms
Hello World. 100  // At 400ms
Hello World. 100  // At 500ms
Hello World. 200  // At 700ms
Hello World. 200  // At 900ms
Hello World. 200  // At 1100ms
...

要求: 只能用 setInterval (不能用 setTimeout),并且只能用一個 if 語句。

解決方案

因為只能用 setInterval ,所以在這里需要通過遞歸來增加下一次 setInterval 調用的延遲。另外還需要一個 if 語句,用來控制在對該遞歸函數的 5 次調用之后執(zhí)行該操作。

下面的解決方案供你參考:

let lastIntervalId, counter = 5;const greeting = delay => {
  if (counter === 5) {
    clearInterval(lastIntervalId);
    lastIntervalId = setInterval(() => {
      console.log('Hello World. ', delay);
      greeting(delay + 100);
    }, delay);
    counter = 0;
  }counter += 1;
};greeting(100);

感謝各位的閱讀!關于關于javascript計時器的案例分析就分享到這里了,希望以上內容可以對大家有一定的幫助,讓大家可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到吧!


當前名稱:關于javascript計時器的案例分析-創(chuàng)新互聯
分享鏈接:http://weahome.cn/article/dsieci.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部