Javascript 设置一个长时间的计时器,即几分钟
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/44603362/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Setting a timer for a long period of time, i.e. multiple minutes
提问by Sedric Heidarizarei
I want to use firebase auth with react native for Loginand Signupbut I got a yellow error:
我想将 firebase auth 与 react native for 结合使用Login,Signup但出现黄色错误:
Setting a timer for a long period of time, i.e. multiple minutes, is a performance and correctness issue on Android as it keeps the timer module awake, and timers can only be called when the app is in the foreground. See (https://github.com/facebook/react-native/issues/12981) for more info. (Saw setTimeout with duration 111862ms)
将计时器设置为长时间(即几分钟)是 Android 上的性能和正确性问题,因为它会使计时器模块保持唤醒状态,并且计时器只能在应用程序处于前台时调用。有关更多信息,请参阅(https://github.com/facebook/react-native/issues/12981)。(看到持续时间为 111862ms 的 setTimeout)
How Can I Fix That?
I don't want to ignore that, I want to understand this error and solve that with the best and Standard way.
And This is my Code:
我该如何解决?
我不想忽略这一点,我想了解这个错误并以最佳和标准的方式解决这个问题。
这是我的代码:
export default class Login extends Component {
constructor(props) {
super(props)
this.state = {
email: '',
password: '',
response: ''
}
this.signUp = this.signUp.bind(this)
this.login = this.login.bind(this)
}
async signUp() {
try {
await firebase.auth().createUserWithEmailAndPassword(this.state.email, this.state.password)
this.setState({
response: 'Account Created!'
})
setTimeout(() => {
this.props.navigator.push({
id: 'App'
})
}, 1500)
} catch (error) {
this.setState({
response: error.toString()
})
}
}
async login() {
try {
await firebase.auth().createUserWithEmailAndPassword(this.state.email, this.state.password)
this.setState({
response: 'user login in'
})
setTimeout(() => {
this.props.navigator.push({
id: 'App'
})
})
} catch (error) {
this.setState({
response: error.toString()
})
}
}
render() {
return (
<View style={styles.container}>
<View style={styles.containerInputes}>
<TextInput
placeholderTextColor="gray"
placeholder="Email"
style={styles.inputText}
// onChangeText={(email) => this.setState({ email })}
onChangeText={(email) => {console.log(email);}}
/>
<TextInput
placeholderTextColor="gray"
placeholder="Password"
style={styles.inputText}
password={true}
onChangeText={(password) => this.setState({ password })}
/>
</View>
<TouchableHighlight
onPress={this.login}
style={[styles.loginButton, styles.button]}
>
<Text
style={styles.textButton}
>Login</Text>
</TouchableHighlight>
<TouchableHighlight
onPress={this.signUp}
style={[styles.loginButton, styles.button]}
>
<Text
style={styles.textButton}
>Signup</Text>
</TouchableHighlight>
</View>
)
}
}
I Reported to Google Firebase Team: (https://github.com/firebase/firebase-js-sdk/issues/97)
我向Google Firebase 团队报告:(https://github.com/firebase/firebase-js-sdk/issues/97)
采纳答案by Sedric Heidarizarei
Josh Crowther Software Engineer at Google Said:
Google 的软件工程师 Josh Crowther 说:
Using multi-step short duration setTimeouts doesn't actually fix the problem though. The Timer module still stays active and the app is still subject to the performance issues indicated in the warning. The issue here is that, we have use cases that require long timers, and react-native doesn't optimize for that use case.
虽然使用多步短持续时间 setTimeouts 实际上并不能解决问题。Timer 模块仍然保持活动状态,应用程序仍然受到警告中指出的性能问题的影响。这里的问题是,我们有需要长时间计时器的用例,而 react-native 没有针对该用例进行优化。
So the net of all that is: This bug can't be fixed here we can only work around the error there are workarounds available (see Setting a timer for a long period of time, i.e. multiple minutes) that disable the warning. Doing the work to disable the warning in our code, doesn't help the issue (beyond disabling the warning), and adds additional SDK code/weight that is completely unnecessary.
因此,总而言之:此错误无法在此处修复,我们只能解决错误,有可用的解决方法(请参阅设置计时器很长一段时间,即多分钟)禁用警告。在我们的代码中禁用警告的工作无助于解决问题(除了禁用警告),并添加了完全不必要的额外 SDK 代码/权重。
I'd recommend chiming in on the issue mentioned above (i.e. facebook/react-native#12981) if you aren't comfortable w/ the workaround provided
如果您对所提供的解决方法感到不舒服,我建议您参与上述问题(即 facebook/react-native#12981)
回答by Jam Risser
This fixes the yellow box and the console log. It even fixes it for Expo.
这修复了黄色框和控制台日志。它甚至为世博会修复了它。
Simply place the following script at the beginning of your codebase.
只需将以下脚本放在代码库的开头即可。
import { YellowBox } from 'react-native';
import _ from 'lodash';
YellowBox.ignoreWarnings(['Setting a timer']);
const _console = _.clone(console);
console.warn = message => {
if (message.indexOf('Setting a timer') <= -1) {
_console.warn(message);
}
};
回答by CLUTCHER
To fix this issue...
要解决此问题...
Navigate to your node_modules/react-native/Libraries/Core/Timers/JSTimers.js file.
Look for the variable MAX_TIMER_DURATION_MS
Change its value to 10000 * 1000
Save the changes (with auto format turned off) and re-build your app.
导航到您的 node_modules/react-native/Libraries/Core/Timers/JSTimers.js 文件。
查找变量 MAX_TIMER_DURATION_MS
将其值更改为 10000 * 1000
保存更改(关闭自动格式)并重新构建您的应用程序。
Found this answer on https://github.com/firebase/firebase-js-sdk/issues/97#issuecomment-485410026
在https://github.com/firebase/firebase-js-sdk/issues/97#issuecomment-485410026上找到了这个答案
回答by Lucas Bustamante
import { YellowBox } from 'react-native';
construct() {
YellowBox.ignoreWarnings(['Setting a timer']);
}
This ignores the warning for me. You should add this to the constructor of every page that shows the warning.
这忽略了对我的警告。您应该将此添加到显示警告的每个页面的构造函数中。
Ignoring it is not the best approach, but if you're using Firebase Realtime Database. They are lookinginto solving this issue with their library, even though the issue is 2 years old.
忽略它不是最好的方法,但如果您使用 Firebase 实时数据库。他们正在研究用他们的图书馆解决这个问题,即使这个问题已经有 2 年了。
回答by Alex Nguyen
I got the same issue and I think it's problem of firebase web SDK so I decided to drop firebase web SDK because it runs in js thread, not react-native thread.
我遇到了同样的问题,我认为这是 firebase web SDK 的问题,所以我决定放弃 firebase web SDK,因为它在 js 线程中运行,而不是 react-native 线程。
And I found react-native-firebase. It's better than firebase web SDK with higher performance and this issue went away
我发现react-native-firebase。它比具有更高性能的 firebase web SDK 更好,这个问题消失了
回答by Jam Risser
Another approach is to use the react-native-ignore-warnings module.
另一种方法是使用 react-native-ignore-warnings 模块。
https://github.com/jamrizzi/react-native-ignore-warnings
https://github.com/jamrizzi/react-native-ignore-warnings
https://www.npmjs.com/package/react-native-ignore-warnings
https://www.npmjs.com/package/react-native-ignore-warnings
This even works for Expo apps.
这甚至适用于 Expo 应用程序。
You would use it the following way . . .
您可以按以下方式使用它。. .
import ignoreWarnings from 'react-native-ignore-warnings';
ignoreWarnings('Setting a timer');
can run with android too..?
也可以用android运行..?
回答by Dave Meehan
In login(), your setTimeout()call is missing an interval value. As a general, browsers now do not fire timeouts/intervals if the window/tab is in the background, or at least they are not expected to be timely. This is to prevent abusive script behaviour, and to reduce power consumption by scripts that may be polling.
在 中login(),您的setTimeout()呼叫缺少间隔值。一般来说,如果窗口/选项卡在后台,浏览器现在不会触发超时/间隔,或者至少他们预计不会及时。这是为了防止滥用脚本行为,并减少可能正在轮询的脚本的功耗。
Your code should work in principle, if the user switches away from the window whilst the timer is running, it will complete when they return. This is probably what you want from a UX point of view, because the users sees the transition, rather than it happening in the background when they are not looking. It helps them maintain mental context.
您的代码原则上应该可以工作,如果用户在计时器运行时离开窗口,当他们返回时它将完成。从 UX 的角度来看,这可能是您想要的,因为用户会看到转换,而不是在他们不看时在后台发生。它帮助他们保持心理环境。
The yellow box is because you are setting an excessively long timer according to the message (nearly two minutes) and that is unlikely to be contextually what you want. The JS environment is warning you that what you are doing it not likely what you intend. You can mute the warning if it is what you want.
黄色框是因为您根据消息(近两分钟)设置了一个过长的计时器,这在上下文中不太可能是您想要的。JS 环境警告您,您正在做的事情不太可能是您想要的。如果这是您想要的,您可以将警告静音。
回答by Cristo Rabani
Work around issue with yellow warning 'Setting a timer' .
解决黄色警告“设置计时器”的问题。
copy & import following file (as fast as you can ;-))
复制并导入以下文件(尽可能快;-))
import {Platform, InteractionManager} from 'react-native';
const _setTimeout = global.setTimeout;
const _clearTimeout = global.clearTimeout;
const MAX_TIMER_DURATION_MS = 60 * 1000;
if (Platform.OS === 'android') {
// Work around issue `Setting a timer for long time`
// see: https://github.com/firebase/firebase-js-sdk/issues/97
const timerFix = {};
const runTask = (id, fn, ttl, args) => {
const waitingTime = ttl - Date.now();
if (waitingTime <= 1) {
InteractionManager.runAfterInteractions(() => {
if (!timerFix[id]) {
return;
}
delete timerFix[id];
fn(...args);
});
return;
}
const afterTime = Math.min(waitingTime, MAX_TIMER_DURATION_MS);
timerFix[id] = _setTimeout(() => runTask(id, fn, ttl, args), afterTime);
};
global.setTimeout = (fn, time, ...args) => {
if (MAX_TIMER_DURATION_MS < time) {
const ttl = Date.now() + time;
const id = '_lt_' + Object.keys(timerFix).length;
runTask(id, fn, ttl, args);
return id;
}
return _setTimeout(fn, time, ...args);
};
global.clearTimeout = id => {
if (typeof id === 'string' && id.startsWith('_lt_')) {
_clearTimeout(timerFix[id]);
delete timerFix[id];
return;
}
_clearTimeout(id);
};
}
回答by Santanu Karar
I think the most close-aide solution to this problem (until RN fixed this internally) is the solution mentioned here.
我认为解决这个问题最贴切的解决方案(直到 RN 在内部修复了这个问题)是这里提到的解决方案。
// add this code to your project to reset all timeouts
const highestTimeoutId = setTimeout(() => ';');
for (let i = 0; i < highestTimeoutId; i++) {
clearTimeout(i);
}
Being used that - against Firebase call I still receive one yellow box warning (on settimeout), but any concurrent warnings never come thereafter. I'm not sure calling this at which point may not trigger the only warning also, but not any concurrent warning throws anymore after Firebase's asynccalls.
使用它 - 针对 Firebase 调用,我仍然收到一个黄框警告(在 settimeout 时),但此后再也不会出现任何并发警告。我不确定此时调用它可能不会触发唯一的警告,但在 Firebaseasync调用后不再引发任何并发警告。
回答by Saurabh Kataria
Facing the same issue.. Seems like, we'd have to hide the warning for the time being. Here's the shortest way to do it:
面临同样的问题.. 看来,我们必须暂时隐藏警告。这是执行此操作的最短方法:
componentDidMount() { console.disableYellowBox = true; ... }

