有关JavaScript计时器的更多信息

电脑杂谈  发布时间:2020-06-01 08:13:24  来源:网络整理

android 定时提醒_android 定时执行_android 全局定时器

简介: JavaScript计时器是窗口的对象接口,而不是JavaScript的一部分. 它的功能是由浏览器实现的,并且在不同的浏览器中会有所不同. 计时器也可以由node.js运行时本身实现.

几周前我在Twitter上发布了这样的采访问题:

JavaScript面试问题:

在哪里可以找到setTimeout和setInterval的源代码? (他们在哪里实现的?)

您在面试中如何回答? (您无法搜索)

函数setTimeOut(回调

Twitter的答案的前半部分是错误的. 答案不是V8(或其他虚拟机!)android 全局定时器,尽管著名的“ JavaScript计时器”功能(如setTimeout和setInterval)不是ECMAScript规范或任何JavaScript实现的一部分. 计时器功能由浏览器实现,不同浏览器的实现方式会有所不同. 计时器也可以由Node.js运行时本身实现.

浏览器中的主要计时器功能是Window对象的接口. Window对象还具有许多其他方法和对象. 此接口使所有元素在JavaScript的全局范围内可用. 这就是为什么您可以直接在浏览器控制台中执行setTimeout的原因.

在节点中,计时器是全局对象的一部分,这与浏览器中的Window非常相似. 您可以在Node中查看计时器的源代码.

有些人可能认为这是一个不好的面试问题-为什么您必须知道这个问题? !作为JavaScript开发人员,我认为您应该知道这一点,因为如果您不这样做,则可能表示您不完全了解V8(和其他虚拟机)如何与浏览器和Node交互.

让我们开始做一些有关计时器功能的例子和挑战吗?

更新: 本文现在是“ Node.js的完整介绍”的一部分. 您可以在此处阅读最新版本.

计时器功能是高阶功能,可用于延迟或重复执行其他功能(它们作为第一个参数接收).

这是延迟的示例:

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

此示例使用setTimeout将问候语延迟4秒. setTimeout的第二个参数是延迟(多少毫秒). 这就是为什么我用4 * 1000代表4秒

setTimeout的第一个参数是一个将延迟执行的函数

android 定时执行_android 定时提醒_android 全局定时器

如果在节点环境中执行example1.js. 节点将暂停4秒钟,然后打印问候语(然后退出).

请注意,setTimeout的第一个参数只是一个函数引用. 它不必像example1.js这样的内联函数. 这是不使用内联函数的相同示例:

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

如果使用setTimeout延迟的函数需要携带参数,我们可以将参数放入setTimeout(在两个已知参数之后),以将参数传递给需要延迟的函数.

// For: func(arg1, arg2, arg3, ...)
// We can use: setTimeout(func, delay, arg1, arg2, arg3, ...)

例如:

// example2.js
const rocks = who => {
  console.log(who + ' rocks');
};
setTimeout(rocks, 2 * 1000, 'Node.js');

上面的代码以2秒的延迟执行,接收who参数并将字符串“ Node.js”通过setTimeout传递给函数的who参数.

在节点环境中执行example2.js控制台将在2秒后显示“ Node.js岩石”

使用到目前为止所学的关于setTimeout的知识,并在相应的延迟后打印以下2条消息.

约束: 您只能在解决方案中定义一个函数,包括内联函数. 这意味着许多setTimeout调用必须使用完全相同的函数.

这是我解决此挑战的方法:

// solution1.js
const theOneFunc = delay => {
  console.log('Hello after ' + delay + ' seconds');
};
setTimeout(theOneFunc, 4 * 1000, 4);
setTimeout(theOneFunc, 8 * 1000, 8);

我要求OneFunc接收延迟参数,并在打印的消息中使用延迟参数的值. 这样,该函数可以根据传递给它的任何延迟值打印不同的消息.

然后,我在两次调用setTimeout中使用了oneFunc,一个在4秒后触发,另一个在8秒后触发. 这两个setTimeout调用还获得了第三个参数,以表示OneFunc的delay参数.

使用node命令执行solution1.js文件将打印出质询所需的内容,第一条消息在4秒钟后,第二条消息在8秒钟后.

如果我要求您每4秒打印一条消息怎么办?

android 全局定时器_android 定时执行_android 定时提醒

尽管您可以将setTimeout放入循环中,但定时器API还提供了setInterval函数,该函数可以满足始终执行某项操作的要求.

这是setInterval的示例:

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

此示例将每3秒打印一条消息. 使用node命令执行example3.js将使Node永远打印此消息,直到您终止该过程(使用CTRL + C).

由于调用计时器函数可以调度操作,因此您可以在执行操作之前取消该操作.

对setTimeout的调用返回一个计时器“ ID”,可以将计时器ID与clearTimeout调用一起使用来取消计时器. 这是这个例子:

// example4.js
const timerId = setTimeout(
  () => console.log('You will not see this one!'),
  0
);
clearTimeout(timerId);

这个简单的计时器应在“ 0”毫秒后触发(使其立即生效),但不会,因为我们正在捕获timerId值并在使用clearTimeout调用后立即将其取消.

当我们使用node命令执行example4.js时,Node将不打印任何内容,并且进程将退出.

在Node.js中,还有另一种使用0ms来执行setTimeout的方法. Node.js计时器API具有另一个名为setImmediate的函数,该函数与setTimeout基本上相同,但为0ms,但我们不必在那里指定延迟:

setImmediate(
  () => console.log('I am equivalent to setTimeout with 0 ms'),
);

并非所有浏览器都支持setImmediate方法. 不要在前端代码中使用它.

像clearTimeout一样,还有一个clearInterval函数android 全局定时器,它对setInerval调用和clearImmediate调用执行相同的操作.

在前面的示例中,您是否注意到用setTimeout在“ 0”毫秒后执行内容并不意味着立即(在setTimeout行之后)执行内容,而是在脚本中的所有其他内容立即执行后(包括clearTimeout调用)立即执行?

让我用一个例子清楚地说明这一点. 这是一个简单的setTimeout调用,应在半秒钟后触发,但不会:

// example5.js
setTimeout(
  () => console.log('Hello after 0.5 seconds. MAYBE!'),
  500,
);
for (let i = 0; i < 1e10; i++) {
  // Block Things Synchronously
}

在此示例中定义了计时器之后,我们使用了一个大的for循环来同步运行时. 1e10是1之后的10个零,因此循环是一个100亿的滴答周期(基本上是模拟一个繁忙的CPU). 在此循环中,节点无法执行任何操作.

android 定时提醒_android 定时执行_android 全局定时器

这在实践中当然是一件很糟糕的事情,但是它将帮助您理解setTimeout延迟不是保证的事情,而是最小的事情. 500ms表示最小延迟为500ms. 实际上,该脚本将花费更长的时间来打印其问候语. 它必须等待阻塞循环完成.

编写脚本以每秒打印一次消息“ Hello World”,但仅打印5次. 5次后,脚本应打印消息“完成”,并让节点进程退出.

限制: 您不能使用setTimeout调用来完成此挑战. 提示: 您需要一个柜台.

这是我解决此问题的方法:

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

我将计数器值设为0,然后在捕获其ID的同时启动setInterval调用.

延迟功能将打印消息并每次增加计数器. 在delay函数中,if语句将检查我们是否在5次内. 如果是这样,它将打印“完成”并使用捕获的intervalId常数清除间隔. 间隔延迟为“ 1000”毫秒.

在常规函数中使用JavaScript的this关键字时,它看起来像这样:

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

此关键字中的值将表示函数的调用方. 如果以上功能在Node REPL中定义,则调用方将是全局对象. 如果该功能是在浏览器的控制台中定义的,则调用者将是窗口对象.

让我们将函数定义为对象的属性以使其更清晰:

const obj = { 
  id: '42',
  whoCalledMe() {
    console.log('Caller is', this);
  }
};
// The function reference is now: obj.whoCallMe

现在,当您使用其引用直接调用obj.whoCallMe函数时,调用者将是obj对象(由其ID标识):

现在,问题是,如果我们将obj.whoCallMe的引用传递给setTimetout调用,调用者将是什么?

//  What will this print??
setTimeout(obj.whoCalledMe, 0);

在这种情况下谁是呼叫者?

android 全局定时器_android 定时提醒_android 定时执行

答案因在何处执行计时器功能而异. 在这种情况下,您根本无法依赖呼叫者是谁. 您将失去对调用者的控制,因为计时器实现现在将成为调用您的函数的实现. 如果在Node REPL中对其进行测试,您将获得一个Timetout对象作为调用者:

请注意,只有在常规函数中使用JavaScript的this关键字时,这才有意义. 如果使用箭头功能,则完全不必担心调用方.

编写脚本,以不同的延迟连续打印消息“ Hello World”. 从1秒的延迟开始,然后每次增加1秒的延迟. 第二次时间将延迟2秒. 第三次将延迟3秒,依此类推.

延迟时间包含在打印的消息中. 预期的输出如下:

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

约束: 您只能使用const定义变量. 您不能使用let或var.

由于此挑战中的延迟量是变量,因此我们不能在此处使用setInterval,但可以在递归调用中使用setTimeout手动创建要执行的间隔. 使用setTimeout的第一个执行函数将创建另一个计时器,依此类推.

此外,因为我们不能使用let / var,所以我们没有计数器来增加每个递归调用的延迟时间,但是我们可以使用递归函数参数在递归调用期间递增.

这是解决此难题的一种可能方法:

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

编写脚本以连续打印消息“ Hello World”,该消息具有与Challenge#3相同的可变延迟概念,但是这次是每个主要延迟间隔5个消息组. 从前5条消息的延迟时间为100毫秒开始,接下来的5条消息的延迟时间为200毫秒,然后是300毫秒,依此类推.

以下是代码要求:

在打印的消息中包含延迟. 预期的输出如下所示(不带注释):

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调用的延迟. 此外,仅在调用递归函数5次之后,才需要一条if语句来控制此操作.

以下是解决方案之一:

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);

感谢您阅读.

本文是从博客园转移过来的,原始地址为:


本文来自电脑杂谈,转载请注明本文网址:
https://www.pc-fly.com/a/jisuanjixue/article-229764-1.html

    相关阅读
      发表评论  请自觉遵守互联网相关的政策法规,严禁发布、暴力、反动的言论

      热点图片
      拼命载入中...