如何使JavaScript休眠或等待


Posted in Javascript onApril 27, 2021

概述

JavaScript不具有 sleep()函数,该函数会导致代码在恢复执行之前等待指定的时间段。如果需要JavaScript等待,该怎么做呢?

假设您想将三则消息记录到Javascript控制台,每条消息之间要延迟一秒钟。JavaScript中没有 sleep() 方法,所以你可以尝试使用下一个最好的方法 setTimeout()。

不幸的是,setTimeout() 不能像你期望的那样正常工作,这取决于你如何使用它。你可能已经在JavaScript循环中的某个点上试过了,看到 setTimeout() 似乎根本不起作用。

问题的产生是由于将 setTimeout() 误解为 sleep() 函数,而实际上它是按照自己的一套规则工作的。

浏览一下 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,而无需外部库或框架。

以上就是如何使JavaScript休眠或等待的详细内容,更多关于JavaScript休眠或等待的资料请关注三水点靠木其它相关文章!

Javascript 相关文章推荐
javascript 命名规则 变量命名规则
Feb 25 Javascript
再谈querySelector和querySelectorAll的区别与联系
Apr 20 Javascript
通过JS自动隐藏手机浏览器的地址栏实现原理与代码
Jan 02 Javascript
Javascript基础教程之数据类型 (布尔型 Boolean)
Jan 18 Javascript
javascript操作select元素实例分析
Mar 27 Javascript
使用JavaScript为Kindeditor自定义按钮增加Audio标签
Mar 18 Javascript
Bootstrap实现导航栏的2种方式
Nov 28 Javascript
jquery对所有input type=text的控件赋值实现方法
Dec 02 Javascript
vue.js树形组件之删除双击增加分支实例代码
Feb 28 Javascript
微信自定义分享链接信息(标题,图片和内容)实现过程详解
Sep 04 Javascript
vue实现图片上传功能
May 28 Javascript
微信小程序入门之指南针
Oct 22 Javascript
JavaScript 实现页面滚动动画
如何用JS实现网页瀑布流布局
分享几个JavaScript运算符的使用技巧
Apr 24 #Javascript
JavaScript 防篡改对象的用法示例
Apr 24 #Javascript
jquery插件实现悬浮的菜单
jquery插件实现代码雨特效
Apr 24 #jQuery
jquery插件实现搜索历史
Apr 24 #jQuery
You might like
PHP操作Memcache实例介绍
2013/06/14 PHP
深入浅析PHP7.0新特征(五大新特征)
2015/10/29 PHP
抛弃 PHP 代价太高
2016/04/26 PHP
php制作圆形用户头像的实例_自定义封装类源代码
2017/09/18 PHP
分享一个asp.net pager分页控件
2012/01/04 Javascript
jquery动态增加text元素以及删除文本内容实例代码
2013/07/01 Javascript
jquery实现在页面加载的时自动为日期插件添加当前日期
2014/08/20 Javascript
JQuery中使用on方法绑定hover事件实例
2014/12/09 Javascript
AngularJS实现表单手动验证和表单自动验证
2015/12/09 Javascript
详解js的延迟对象、跨域、模板引擎、弹出层、AJAX【附实例下载】
2016/12/19 Javascript
jQuery ajax的功能实现方法详解
2017/01/06 Javascript
js/jq仿window文件夹移动/剪切/复制等操作代码
2017/03/08 Javascript
关于Angular2 + node接口调试的解决方案
2017/05/28 Javascript
vue树形结构获取键值的方法示例
2018/06/21 Javascript
JavaScript碎片—函数闭包(模拟面向对象)
2019/03/13 Javascript
百度小程序自定义通用toast组件
2019/07/17 Javascript
Vue调用后端java接口的实例代码
2019/10/28 Javascript
vue 根据选择条件显示指定参数的例子
2019/11/09 Javascript
[03:04]DOTA2英雄基础教程 影魔
2013/12/11 DOTA
[04:04]DOTA2亚洲邀请赛比赛场馆&酒店全攻略
2017/03/23 DOTA
[56:58]VP vs Optic 2018国际邀请赛小组赛BO2 第一场 8.16
2018/08/17 DOTA
[01:33:25]DOTA2-DPC中国联赛 正赛 Elephant vs IG BO3 第一场 1月24日
2021/03/11 DOTA
Python中os.path用法分析
2015/01/15 Python
Python RuntimeError: thread.__init__() not called解决方法
2015/04/28 Python
Python中的super()方法使用简介
2015/08/14 Python
python数据类型_元组、字典常用操作方法(介绍)
2017/05/30 Python
Python-openCV开运算实例
2020/07/05 Python
linux系统下pip升级报错的解决方法
2021/01/31 Python
HTML5手机端弹出遮罩菜单特效代码
2016/01/27 HTML / CSS
金牌葡萄酒俱乐部:Gold Medal Wine Club
2017/11/02 全球购物
APM Monaco中国官网:来自摩纳哥珠宝品牌
2017/12/27 全球购物
客户经理竞聘演讲稿
2014/05/15 职场文书
目标责任书格式范文
2015/05/11 职场文书
2016年乡镇综治宣传月活动总结
2016/03/16 职场文书
介绍信应该怎么开?
2019/04/03 职场文书
中学生打架检讨书之500字
2019/08/06 职场文书