我做了一些关于循环和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);
}
答案 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...of
和object 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 loop
。 call stack/event loop
将所有这些都放在clearTimeout( timer )
中,并且所有这些都将在5000毫秒后执行,因为这是设置超时的结果,因此它会将代码的执行时间安排为5000毫秒现在为所有人。
我建议你观看 Philip Roberts 的精彩讲座 Philip Roberts: What the heck is the event loop anyway
如果您希望使用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 是链接的索引