JavaScript实现类似sleep()的多种方式

编写复杂的JavaScript脚本时,有时会有需求希望脚本能停滞指定的一段时间,类似于 java 中的 Thread.sleep 或者 sh 脚本中的 sleep 命令所实现的效果。

很多语言都有sleep函数,sleep() 方法的作用是在指定的毫秒数内让当前“正在执行的线程”休眠(暂停执行)但是JavaScript中并没有提供类似于 Java 的线程控制的功能, 虽然有 setTimeout 和 setInterval 两个方法可以做一些定时执行控制,但并不能满足所有的要求。

因为setTimeout的本质不是延迟多长时间执行,而是将事件插入了"任务队列",必须等到当前代码(执行栈)执行完,主线程才会去执行它指定的回调函数,要是当前代码耗时很长,有可能要等很久,所以并没有办法保证回调函数一定会在setTimeout()指定的时间执行。其次setTimeout是通过回调函数来实现定时任务的,所以在多任务的场景下就会出现回调嵌套,代码很不优雅,可读性差等问题。下面介绍JavaScript实现类似sleep的多种方式。

一、基于循环实现sleep

// 使用while循环
function sleep(delay) {
    var start = new Date().getTime();
    while (new Date().getTime() - start < delay) {
        continue;
    }
}

console.log(1, new Date().getTime())  // 1 1631671203441
sleep(2000)
console.log(2, new Date().getTime())  // 2 1631671205441
// 使用for循环
function sleep(delay) {
    for (var start = Date.now();  Date.now() - start<= delay;);
}

console.log(1, new Date().getTime()) // 1 1631671672290
sleep(2000)
console.log(2, new Date().getTime()) // 2 1631671674290

优点:简单粗暴,通俗易懂。

缺点:以上的代码不会让线程休眠,而是通过高负荷计算使cpu无暇处理其他任务。这样做的缺点是在sleep的过程中其他所有的任务都会被暂停,包括dom的渲染。所以sleep的过程中程序会处于假死状态,并不会去执行其他任务

二、基于Promise实现sleep

// 使用promise
function sleep(delay) {
    return new Promise(resolve =>
        setTimeout(resolve, delay)
    )
}

console.log(1, new Date().getTime())     // 1 1631672405810
sleep(2000).then(() => {
    console.log(2, new Date().getTime()) // 2 1631672407810
})

优点:这种方式实际上是用了 setTimeout,没有形成进程阻塞,不会造成性能和负载问题。

缺点:虽然不像 callback 套那么多层,但仍不怎么美观,而且当我们需要在某过程中需要停止执行(或者在中途返回了错误的值),还必须得层层判断后跳出,非常麻烦,而且这种异步并不是那么彻底,还是看起来别扭。

三、基于generate实现sleep

// 使用Generator
function* sleep(delay) {
    yield new Promise(function (resolve, reject) {
        setTimeout(resolve, delay);
    })
}

console.log(1, new Date().getTime())     // 1 1631673104689
sleep(2000).next().value.then(() => {
    console.log(2, new Date().getTime()) // 2 1631673106689
})

优点:同 Promise 优点,另外代码就变得非常简单干净

缺点:但不足也很明显,就是每次都要执行 next() 显得很麻烦,虽然有co(第三方包)可以解决,但就多包了一层不好看,错误也必须按co的逻辑来处理不爽。

四、基于 Async/Await 实现sleep

// 使用async/await
function sleep(delay) {
    return new Promise((resolve) => setTimeout(resolve, delay));
}
async function test() {
    console.log(1, new Date().getTime()) // 1 1631686674068
    await sleep(2000);
    console.log(2, new Date().getTime()) // 2 1631686676068
}
test();

优点:同 Promise 和 Generator 优点。 Async/Await 可以看做是 Generator 的语法糖,Async 和 Await 相较于 * 和 yield 更加语义,另外各个函数都是扁平的,不会产生多余的嵌套,代码更加清爽易读。

缺点: ES7 语法存在兼容性问题,但有 babel 一切兼容性都不是问题

五、使用npm上的node-sleep包

// 引入sleep包
var sleep = require('sleep');
console.log('1');
sleep.sleep(2); //休眠2秒钟
console.log('2');
sleep.msleep(2000); //休眠2000毫秒 = 2秒
console.log('3');
sleep.usleep(2000000) //休眠2000000微秒 = 2秒
console.log('4');

优点:能够实现更加精细的时间精确度,而且看起来就是真的 sleep 函数,清晰直白。

缺点:需要安装这个模块

地址:node-sleep

 文章每周持续更新,可以微信搜索「 前端大集锦 」第一时间阅读,回复【视频】【书籍】领取200G视频资料和30本PDF书籍资料

 

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

@Demi

您的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值