JavaScript休眠/延迟/等待函数

28

如果此问题之前已经在这里问过,我很抱歉,我没有找到合适的答案。

我想创建一个JavaScript的睡眠/延迟/等待函数,我可以在脚本的任何地方调用它,就像jQuery的.delay()一样。

由于我有一个通过php生成的脚本,所以我不能使用setTimeout,并将其放入两个不同的函数中,其中间有超时。我需要创建一个函数,允许我执行

alert("time started");
sleep(4000);
alert("time up");

真的不想使用jQuery。


1
不,你不能这样做。就是这么简单。使用setTimeout或类似的解决方案。 - Denys Séguret
你不能使用setTimeout的原因没有道理。你可以让一个函数在setTimeout延迟后调用另一个函数。展示一下不能用setTimeout的代码,我们或许能够帮助你。 - Hamza Kubba
1
无论你喜不喜欢,setTimeout都是正确的答案。如果你需要延迟,你需要重新构建你的页面或函数来处理它。 - Hamza Kubba
1
@user2704237,这篇文章读起来像是你正在尝试实现一种基于JavaScript的新高级语言。如果它是基于JavaScript的,那么你不能实现与JavaScript根本不同的东西。 - Paul S.
显示剩余5条评论
6个回答

25

这是一个使用新的async/await语法的解决方案。

async function testWait() {
    alert('going to wait for 5 second');
    await wait(5000);
    alert('finally wait is over');
}

function wait(time) {
    return new Promise(resolve => {
        setTimeout(resolve, time);
    });
}

注意:您只能在异步函数中调用wait函数。


1
不必创建一个调用 resolve() 的函数,你可以直接用 resolve 函数本身替换它:将 () => { resolve(); } 替换为 resolve - Coco Liliace

17

很遗憾,您不能仅仅添加一个函数来暂停Javascript。

您必须使用 setTimeout() 函数。

示例:

function startTimer () {
    timer.start();
    setTimeout(stopTimer,5000);
}

function stopTimer () {
    timer.stop();
}

编辑:

对于你自己生成的倒计时,它同样很简单。

HTML:

<input type="number" id="delay" min="1" max="5">

JS:

JS(JavaScript):
var delayInSeconds = parseInt(delay.value);
var delayInMilliseconds = delayInSeconds*1000;

function startTimer () {
    timer.start();
    setTimeout(stopTimer,delayInMilliseconds);
}

function stopTimer () {
    timer.stop;
}

现在你只需要为startTimer()添加一个触发器,比如onchange


“timer”应该是什么?我遇到了一个未捕获的引用错误:未定义“timer”。 - gicalle
timer.start() 和 timer.stop() 是占位函数。请用您想要的任何命令替换它们。 - Deep
现在你可以在ES2015 + async/await中实现。 - Dan Dascalescu

10

你需要使用setTimeout,所以我认为你的问题是:

我有一个由PHP生成的脚本,因此无法将其放入两个不同的函数中。

是什么阻止了您在脚本中生成两个函数?

function fizz() {
    var a;
    a = 'buzz';
    // sleep x desired
    a = 'complete';
}

可以重写为:

function foo() {
    var a; // variable raised so shared across functions below
    function bar() { // consider this to be start of fizz
        a = 'buzz';
        setTimeout(baz, x); // start wait
    } // code split here for timeout break
    function baz() { // after wait
        a = 'complete';
    } // end of fizz
    bar(); // start it
}

你会注意到在调用 baz 时内部的 a 起始值为 buzz,而在调用结束后,foo 内部的 a 将变为 "complete"

基本上,将所有内容都包装在一个函数中,将所有变量移到该包装函数中,以便包含的函数可以继承它们。然后,每当遇到 wait NUMBER seconds,就要 echo 一下 setTimeout,结束当前的函数并开始一个新的函数以继续之前的工作。


2

由于当前浏览器中JS的实现方式,无法精确按照您所指定的行为进行操作。抱歉。

理论上,您可以编写一个带有循环的函数,其中循环结束条件基于时间,但这将占用您的CPU,使浏览器无响应,并且是极其低效的设计。我甚至拒绝为此编写示例;)


更新:我的回答被评为-1(不公平),但我想提到在ES6中(尚未在浏览器中实现,也没有默认启用Node.js),将能够以同步方式编写异步代码。您需要使用promises和generators。

例如,在Node.js中使用harmony标志可以立即使用它,使用Q.spawn(),请参见此博客文章中的示例(最后一个示例)。


是啊,我不知道为什么我的答案被评为-1。我很想看到OP编写的代码在ES5浏览器中运行。当你展示它时,请随意给我打负分。 - kamituel
这是正确的想法。由于这个问题是一个重复的问题,我在原始问题上留下了一个基于ES6的答案 - Dan Dascalescu

1
你可以使用这个 -
function sleep(milliseconds) {
    var start = new Date().getTime();
    for (var i = 0; i < 1e7; i++) {
        if ((new Date().getTime() - start) > milliseconds){
            break;
        }
    }
}

在需要延迟的地方调用此函数,例如 sleep(1000); - Tushar
2
自旋等待?哎呀。那会对移动设备造成伤害。 - Nathan Tuggy
1
这个不起作用,因为for循环的条件可能会很快满足。即使你移除了for循环的条件(例如for(;;){...}),你最终还是会阻塞单线程,从而影响DOM。 - Auxiliary
导致我的Chrome浏览器锁定并消耗过多资源。不好。 - CodingMatters

0
您可以使用以下代码,它会递归调用函数以便正确等待所需的时间。
function exportar(page,miliseconds,totalpages)
{
    if (page <= totalpages)
    {
        nextpage = page + 1;
        console.log('fnExcelReport('+ page +'); nextpage = '+ nextpage + '; miliseconds = '+ miliseconds + '; totalpages = '+ totalpages );
        fnExcelReport(page);
        setTimeout(function(){
            exportar(nextpage,miliseconds,totalpages);
        },miliseconds);
    };
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接