循环中 Promise 的 javascript 睡眠功能

Posted

技术标签:

【中文标题】循环中 Promise 的 javascript 睡眠功能【英文标题】:javascript sleep function by Promise in loop 【发布时间】:2018-01-19 14:08:36 【问题描述】:

我打算在firefox中打开一系列url,每个url应该在10分钟内一个接一个地打开,这是我的代码应该在firebug控制台中执行:

function sleep (time) 
    return new Promise((resolve) => setTimeout(resolve, time));

var urls = ["https://www.google.com/","https://www.bing.com/","https://www.reddit.com/"];
for(var i = 0; i < urls.length; i++)
    sleep(600000 * i).then(() => 
    window.open(urls[i]); 
)

但它没有用,有人可以帮助我吗?谢谢~

【问题讨论】:

见:***.com/q/750486/5647260 【参考方案1】:

Sleep 函数正在执行异步for 循环在执行任何sleep 调用之前完成。

因此,for 循环的最后一个值将是3,而window.open 函数将接收未定义的valuevalue 作为参数。

看看:

function sleep (time) 
    return new Promise((resolve) => setTimeout(resolve, time));

var urls = ["https://www.google.com/","https://www.bing.com/","https://www.reddit.com/"];
for(var i = 0; i < urls.length; i++)
    sleep(600*i).then(() => 
    console.log(i); 
)

一种解决方案是使用let关键字。

您应该使用let 关键字才能使用i 变量的封闭值。

function sleep (time) 
    return new Promise((resolve) => setTimeout(resolve, time));

var urls = ["https://www.google.com/","https://www.bing.com/","https://www.reddit.com/"];
for(let i = 0; i < urls.length; i++)
    sleep(6000*i).then(() => 
    window.open(urls[i]); 
)

jsFiddle solution.

【讨论】:

谢谢亚历克斯,它有效。我发现javascript更难。谢谢大哥~ @Wang,不客气。不要忘记接受答案以帮助其他人。【参考方案2】:

Promises 与 async/await 函数配合得非常好。

以下将声明一个新的异步函数(即在函数被调用后将在外部执行)。异步函数的代码读起来很容易,因为它读起来像一个同步函数:

function sleep(time) 
    return new Promise((resolve) => setTimeout(resolve, time))


(async function() 
    const urls = ["https://www.google.com/","https://www.bing.com/","https://www.reddit.com/"]
    for (let url of urls) 
        await sleep(1000)
        console.log(url)
    
)()
    

这是一个使用 Promise 链接的版本:

function sleep(time) 
    return new Promise((resolve) => setTimeout(resolve, time))


const urls = ["https://www.google.com/","https://www.bing.com/","https://www.reddit.com/"];
let p = Promise.resolve();
for (let url of urls) 
    p = p.then( function () 
        return sleep(1000);
     );
    p = p.then( function () 
        console.log(url);
        return Promise.resolve();
     );

【讨论】:

【参考方案3】:

问题是 i 在所有 3 种情况下都将 =3,因此您需要保存 i 例如

function sleep (time, i) 
    return new Promise((resolve) => setTimeout(() => resolve(i), time));

var urls = ["https://www.google.com/","https://www.bing.com/","https://www.reddit.com/"];
for(var i = 0; i < urls.length; i++)
    sleep(1 * i, i).then((index) => 
    console.log(urls[index]); 
)

但即使这样也无济于事,因为第一个新标签页将打开,您在非活动标签页中的代码将被浏览器停止。

【讨论】:

【参考方案4】:

认为一个区间 + entries 会更适合这个,这里是一个 es6 的例子

const urls = [
  'https://www.google.com/',
  'https://www.bing.com/',
  'https://www.reddit.com'
]

const entries = urls.entries()

const loop = setInterval(() => 
  const value, done = entries.next()
  done ? clearInterval(loop) : open(value)
, 600 * 10)

【讨论】:

【参考方案5】:

您可以使用 setInterval() 或 setTimeout() 代替 sleep 来实现此目的。

【讨论】:

以上是关于循环中 Promise 的 javascript 睡眠功能的主要内容,如果未能解决你的问题,请参考以下文章

Javascript等待Promise在返回响应之前完成for循环

js的事件循环机制:同步与异步任务(setTimeout,setInterval)宏任务,微任务(Promise,process.nextTick)

ES6 promise

JavaScript Promise理解

JavaScript异步处理问题,循环处理异步任务,并拿到数据,Nodejs循环异步任务接口处理

对javascript EventLoop事件循环机制不一样的理解