经过一些研究后,循环和setTimeout函数仍无法正常工作

时间:2017-07-14 20:31:30

标签: javascript

我做了一些关于循环和setTimeout函数的研究,但它仍然无法正常工作......

它会同时打开所有链接,每个链接打开时不会延迟5秒。

我希望在每个链接之后每个链接打开5秒延迟。

代码:

var links = document.querySelectorAll('a[class="mn-person-info__link ember-view"][id^="ember"]')
for (var i = 1; i <= links.length; i++) {
    (function(index) {
        setTimeout(function() { 
            window.open(links[index].href,'_blank'); 
        }, 5000);
    })(i);
}

5 个答案:

答案 0 :(得分:4)

使用Promise链和Array#reduce(),您可以执行以下操作:

var links = document.querySelectorAll('a[class="mn-person-info__link ember-view"][id^="ember"]');

Array.from(links).reduce((chain, { href }) => {
  return chain.then(() => new Promise(resolve => {
    window.open(href, '_blank');
    setTimeout(resolve, 5000);
  }));
}, Promise.resolve())

如果您不想做一些非常有趣的事情并且可以立即设置所有超时,则可以使用let代替for来简化var循环和IIFE

var links = document.querySelectorAll('a[class="mn-person-info__link ember-view"][id^="ember"]');

for (let i = 0; i < links.length; i++) {
  setTimeout(function() { 
    window.open(links[i].href, '_blank'); 
  }, 5000 * i);
}

甚至更简单,使用for...ofobject destructuring

var links = document.querySelectorAll('a[class="mn-person-info__link ember-view"][id^="ember"]');
var i = 0;

for (const { href } of links) {
  setTimeout(function() { 
    window.open(href, '_blank'); 
  }, 5000 * i++);
}

答案 1 :(得分:2)

那是因为所有的超时都是立即设置的,几乎是一次。因此,超时的结束几乎在同一时间发生。试试这个:

var links = document.querySelectorAll('a[class="mn-person-info__link ember-view"][id^="ember"]')

for (var i = 1; i <= links.length; i++) {
  (function(index) {
    setTimeout(function() {
      window .open(links[index].href,'_blank');
    }, 5000 * i);
  })(i);
}

答案 2 :(得分:2)

setTimeout是异步的。我会用以下方法解决这个指定的问题:

Array.from(links).reduce((a,e)=>{
    setTimeout(function() { window .open(e.href,'_blank');}, a);
    return a + 5000;
} ,5000);

答案 3 :(得分:2)

从上面的代码我假设您希望每5秒打开一次链接,所以这里是对您的代码进行的改进和建议

Hoisting

此代码的作用是什么?

第一部分是将在此脚本中使用的变量的声明。声明变量id的首选方法是使用hoisting

Timers

  

Hoisting是一种JavaScript机制,在代码执行之前,变量和函数声明被移动到其作用域的顶部。

for loop

如果您希望按顺序打开链接,则应将它们放在一个接一个地调用它们的函数中,而不是使用for loopcall stack/event loop将所有这些都放在clearTimeout( timer )中,并且所有这些都将在5000毫秒后执行,因为这是设置超时的结果,因此它会将代码的执行时间安排为5000毫秒现在为所有人。

我建议你观看 Philip Roberts 的精彩讲座 Philip Roberts: What the heck is the event loop anyway

如果您希望使用setTimeout

,保存setTimeout的返回值将允许您稍后取消计时器

摘要

由于你有一个for循环,它只会循环遍历你的所有链接。 setTimeout将为所有链接设置从现在起5秒的预定执行时间 这里的技巧是在打开当前计时器之后设置下一个计时器。这就是sertTimeout在函数本身内定义的原因。

import React from 'react'; import ReactDOM from 'react-dom'; import {BrowserRouter, Switch, Route} from 'react-router-dom'; import {Home} from './home'; import {Movie} from './movie'; import './css/index.css'; class App extends React.Component { constructor() { super(); this.state = { movie: {} } this.setMovie = this.setMovie.bind(this); } setMovie(newMovie) { this.setState({ movie: newMovie }); } render() { return( <BrowserRouter> <Switch> <PropsRoute path={'/movie/:movieTitle'} movie={this.state.movie} component={Movie} /> <PropsRoute path={'/'} component={Home} setMovie={this.setMovie} /> </Switch> </BrowserRouter> ); } } ReactDOM.render( <App />, document.getElementById('root') ); ----- const renderMergedProps = (component, ...rest) => { const finalProps = Object.assign({}, ...rest); return ( React.createElement(component, finalProps) ); } const PropsRoute = ({ component, ...rest }) => { return ( <Route {...rest} render={routeProps => { return renderMergedProps(component, routeProps, rest); }}/> ); } 得到第三个参数,它是在被调用时传递给函数的参数。

答案 4 :(得分:-2)

简单方法:

links.forEach(function(i, link) {
    setTimeout(function() { 
        window.open(link.href,'_blank'); 
    }, 5000 * i);
});

等待 i * 5 秒,其中 i 是链接的索引