使用JavaScript实现休眠或等候
JavaScript不具有 sleep()
函数,该函数会致使代码在复原施行此前等候指定的时间段。假如需要JavaScript等候,该如何做呢?
假设您想将三则新闻记载到Javascript操纵台,每条新闻之间要延迟一秒钟。JavaScript中没有 sleep()
办法,所以你可以尝试使用下一个最好的办法 setTimeout()
。
不幸的是,setTimeout()
不克不及像你盼望的那样正常工作,这取决于你怎样使用它。你大概已经在JavaScript轮回中的某个点上试过了,看到 setTimeout()
好像基本不起作用。
问题的发生是由于将 setTimeout()
曲解为 sleep()
函数,而实际上它是依照本人的一套规则工作的。
在本文中,我将说明怎样使用 setTimeout()
,包罗怎样使用它来制作一个睡眠函数,使JavaScript暂停施行并在持续的代码行之间等候。
阅读一下 setTimeout()
的文档,它好像需要一个 "延迟 "参数,以毫秒为单位。
回到原始问题,您尝试调取 setTimeout(1000)
在两次调取 console.log()
函数之间等候1秒。
不幸的是 setTimeout()
不克不及这样工作:
setTimeout(1000) console.log(1) setTimeout(1000) console.log(2) setTimeout(1000) console.log(3) for (let i = 0; i <= 3; i++) { setTimeout(1000) console.log(`#${i}`) }
这段代码的结果完全没有延迟,就像 setTimeout()
不存在一样。
回忆文档,你会发明问题在于实际上第一个参数应当是函数调取,而不是延迟。究竟,setTimeout()
实际上不是 sleep()
办法。
你重写代码以将回调函数作为第一个参数并将必需的延迟作为第二个参数:
setTimeout(() => console.log(1), 1000) setTimeout(() => console.log(2), 1000) setTimeout(() => console.log(3), 1000) for (let i = 0; i <= 3; i++) { setTimeout(() => console.log(`#${i}`), 1000) }
这样一来,三个console.log的日志信息在经过1000ms(1秒)的单次延时后,会一起显示,而不是每次反复调取之间延时1秒的抱负结果。
在计议怎样解决此问题此前,让我们更具体地研讨一下 setTimeout()
函数。
检查setTimeout ()
你大概已经留意到上面第二个代码片段中使用了箭头函数。这些是必需的,由于你需要将匿名回调函数传递给 setTimeout()
,该函数将在超时后运转要施行的代码。
在匿名函数中,你可以指定在超不时间后施行的任意代码:
// 使用箭头语法的匿名回调函数。 setTimeout(() => console.log("你好!"), 1000) // 这等同于使用function关键字 setTimeout(function() { console.log("你好!") }, 1000)
理论上,你可以只传递函数作为第一个参数,回调函数的参数作为剩余的参数,但对我来说,这好像从来没有准确的工作:
// 应当能用,但不克不及用 setTimeout(console.log, 1000, "你好")
人们使用字符串解决此问题,但是不倡议这样做。从字符串施行JavaScript具有平安隐患,由于任何不妥行动者都可以运转作为字符串注入的任意代码。
// 应当没用,但确实有用 setTimeout(`console.log("你好")`, 1000)
那么,为什么在我们的第一组代码示例中 setTimeout()
失败?仿佛我们在准确使用它,每次都反复了1000ms的延迟。
缘由是 setTimeout()
作为同步代码施行,并且对 setTimeout()
的屡次调取均同时运转。每次调取 setTimeout()
都会创立异步代码,该代码将在给定延迟后稍后施行。由于代码段中的每个延迟都是雷同的(1000毫秒),因此所有排队的代码将在1秒钟的单个延迟后同时运转。
如前所述,setTimeout()
实际上不是 sleep()
函数,取而代之的是,它只是将异步代码排入队列以供今后施行。荣幸的是,可以使用 setTimeout()
在JavaScript中创立本人的 sleep()
函数。
怎样编写sleep函数
通过Promises,async
和 await
的功效,您可以编写一个 sleep()
函数,该函数将按预测运转。
但是,你只能从 async
函数中调取此自定义 sleep()
函数,并且需要将其与 await
关键字一起使用。
这段代码演示了怎样编写一个 sleep()
函数:
const sleep = (delay) => new Promise((resolve) => setTimeout(resolve, delay)) const repeatedGreetings = async () => { await sleep(1000) console.log(1) await sleep(1000) console.log(2) await sleep(1000) console.log(3) } repeatedGreetings()
此JavaScript sleep()
函数的功效与您预测的完全一样,由于 await
致使代码的同步施行暂停,直到Promise被解决为止。
一个简便的选中
别的,你可以在第一次调取 setTimeout()
时指定增添的超不时间。
以下代码等效于上一个示例:
setTimeout(() => console.log(1), 1000) setTimeout(() => console.log(2), 2000) setTimeout(() => console.log(3), 3000)
使用增添超时是可行的,由于代码是同时施行的,所以指定的回调函数将在同步代码施行的1、2和3秒后施行。
它会轮回运转吗?
如你所料,以上两种暂停JavaScript施行的选项都可以在轮回中正常工作。让我们看两个简便的例子。
这是使用自定义 sleep()
函数的代码段:
const sleep = (delay) => new Promise((resolve) => setTimeout(resolve, delay)) async function repeatGreetingsLoop() { for (let i = 0; i <= 5; i++) { await sleep(1000) console.log(`Hello #${i}`) } } repeatGreetingsLoop()
这是一个简便的使用增添超时的代码片段:
for (let i = 0; i <= 5; i++) { setTimeout(() => console.log(`Hello #${i}`), 1000 * i) }
我更喜爱后一种语法,特殊是在轮回中使用。
总结
JavaScript大概没有 sleep()
或 wait()
函数,但是使用内置的 setTimeout()
函数很容易创立一个JavaScript,只要你慎重使用它即可。
就其本身而言,setTimeout()
不克不及用作 sleep()
函数,但是你可以使用 async
和 await
创立自定义JavaScript sleep()
函数。
采纳不一样的办法,可以将交织的(增添的)超时传递给 setTimeout()
来模拟 sleep()
函数。之所以可行,是由于所有对setTimeout()
的调取都是同步施行的,就像JavaScript平常一样。
但愿这可以帮忙你在代码中引入一些延迟——仅使用原始JavaScript,而无需外部库或框架。
祝您编码兴奋!