当前位置: 首页 > 科技观察

如何在JavaScript中实现休眠或等待功能实现休眠功能

时间:2023-03-15 13:19:56 科技观察

JavaScript没有sleep()函数导致代码在恢复执行之前等待指定的时间段。如果需要JavaScript等待怎么办?假设您要将三条消息记录到Javascript控制台,每条消息之间有一秒钟的延迟。JavaScript中没有sleep()方法,因此您可以尝试使用下一个最佳方法setTimeout()。不幸的是,setTimeout()并不像您预期??的那样工作,这取决于您如何使用它。您可能已经在J??avaScript循环中的某个时刻尝试过,发现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(leti=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(leti=0;i<=3;i++){setTimeout(()=>console.log(`#${i}`),1000)}这样,三个console.log的日志信息会在单次延迟1000ms(1秒)后一起显示,而不是重复调用之间延迟1秒的理想效果。在讨论如何解决这个问题之前,让我们更详细地研究一下setTimeout()函数。检查setTimeout()您可能已经注意到在上面的第二个代码片段中使用了箭头函数。这些是必需的,因为您需要将匿名回调函数传递给setTimeout(),它将在超时后运行要执行的代码。在匿名函数中,您可以指定任意代码在超时后执行://Anonymouscallbackfunctionusingarrowsyntax。setTimeout(()=>console.log("Hello!"),1000)//理论上相当于使用函数关键字setTimeout(function(){console.log("Hello!")},1000),您可以将函数作为第一个参数传递,将回调函数的参数作为其余参数传递,但对我来说,这似乎永远无法正常工作://应该可以,但不能使用setTimeout(console.log,1000,"Hello")人们使用字符串来解决这个问题,但不推荐。从字符串执行JavaScript具有安全隐患,因为任何不良行为者都可以运行作为字符串注入的任意代码。//应该没用,但确实有用setTimeout(`console.log("Hello")`,1000)那么,为什么setTimeout()在我们的第一组代码示例中失败了?似乎我们使用正确,每次Repeated每次都有1000毫秒的延迟。原因是setTimeout()作为同步代码执行,并且对setTimeout()的多个调用同时运行。每次调用setTimeout()都会创建异步代码,这些代码将在给定延迟后稍后执行。由于片段中的每个延迟都是相同的(1000毫秒),所有排队的代码将在1秒的单个延迟后并发运行。如前所述,setTimeout()实际上并不是一个sleep()函数,它只是将异步代码排队等待稍后执行。幸运的是,可以使用setTimeout()在JavaScript中创建自己的sleep()函数。如何编写休眠函数借助Promises、async和await的强大功能,您可以编写一个按预期运行的sleep()函数。但是,您只能从异步函数中调用此自定义sleep()函数,并且需要将其与await关键字一起使用。此代码演示了如何编写sleep()函数:constsleep=(delay)=>newPromise((resolve)=>setTimeout(resolve,delay))constrepeatedGreetings=async()=>{awaitsleep(1000)console.log(1)awaitsleep(1000)console.log(2)awaitsleep(1000)console.log(3)}repeatedGreetings()这个JavaScriptsleep()函数的工作方式与您预期的完全一样,因为await会导致代码的同步执行暂停,直到Promise被解决。一个简单的选择。或者,您可以在首次调用setTimeout()时指定增量超时。下面的代码等同于前面的例子:setTimeout(()=>console.log(1),1000)setTimeout(()=>console.log(2),2000)setTimeout(()=>console.log(3),3000)使用递增超时是有效的,因为代码是并发执行的,所以指定的回调函数会在同步代码执行的1、2、3秒后执行。它会循环运行吗?如您所料,上述两个用于暂停JavaScript执行的选项在循环中都可以正常工作。让我们看两个简单的例子。这是使用自定义sleep()函数的代码片段:constsleep=(delay)=>newPromise((resolve)=>setTimeout(resolve,delay))asyncfunctionrepeatGreetingsLoop(){for(leti=0;i<=5;i++){awaitsleep(1000)console.log(`Hello#${i}`)}}repeatGreetingsLoop()这是一个使用递增超时的简单代码片段:for(leti=0;i<=5;i++){setTimeout(()=>console.log(`Hello#${i}`),1000*i)}我更喜欢后一种语法,尤其是在循环中使用时。总结JavaScript可能没有sleep()或wait()函数,但是使用内置的setTimeout()函数很容易创建一个,只要您谨慎使用它。setTimeout()本身不能用作sleep()函数,但您可以使用async和await来创建自定义JavaScriptsleep()函数。采用不同的方法,您可以将交错(增加)超时传递给setTimeout()以模拟sleep()函数。这是有效的,因为所有对setTimeout()的调用都是同步执行的,就像JavaScript通常那样。希望这可以帮助您在代码中引入一些延迟-仅使用原始JavaScript,不使用外部库或框架。