Javascript 长时间设置计时器,即多分钟
我想将firebase auth与react native一起用于Javascript 长时间设置计时器,即多分钟,javascript,firebase,react-native,Javascript,Firebase,React Native,我想将firebase auth与react native一起用于登录和注册,但我得到一个黄色错误: 在Android上,设置一个长时间的计时器(即多分钟)是一个性能和正确性问题,因为它会使计时器模块处于唤醒状态,并且计时器只能在应用程序位于前台时调用。有关更多信息,请参见()。(Saw设置超时,持续时间为111862ms) 我如何解决这个问题? 我不想忽视这一点,我想理解这一错误,并以最佳和标准的方式解决它。 这是我的代码: export default class Login exten
登录
和注册
,但我得到一个黄色错误:
在Android上,设置一个长时间的计时器(即多分钟)是一个性能和正确性问题,因为它会使计时器模块处于唤醒状态,并且计时器只能在应用程序位于前台时调用。有关更多信息,请参见()。(Saw设置超时,持续时间为111862ms)
我如何解决这个问题?我不想忽视这一点,我想理解这一错误,并以最佳和标准的方式解决它。
这是我的代码:
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>
)
}
}
导出默认类登录扩展组件{
建造师(道具){
超级(道具)
此.state={
电子邮件:“”,
密码:“”,
响应:“”
}
this.signUp=this.signUp.bind(this)
this.login=this.login.bind(this)
}
异步注册(){
试一试{
等待firebase.auth().createUserWithEmailAndPassword(this.state.email,this.state.password)
这是我的国家({
响应:“已创建帐户!”
})
设置超时(()=>{
这个是.props.navigator.push({
id:'应用程序'
})
}, 1500)
}捕获(错误){
这是我的国家({
响应:error.toString()
})
}
}
异步登录(){
试一试{
等待firebase.auth().createUserWithEmailAndPassword(this.state.email,this.state.password)
这是我的国家({
响应:“用户登录”
})
设置超时(()=>{
这个是.props.navigator.push({
id:'应用程序'
})
})
}捕获(错误){
这是我的国家({
响应:error.toString()
})
}
}
render(){
返回(
this.setState({email})}
onChangeText={(电子邮件)=>{console.log(电子邮件);}
/>
this.setState({password})}
/>
登录
报名
)
}
}
我向Google Firebase团队报告了同样的问题,我认为这是Firebase web SDK的问题,所以我决定放弃Firebase web SDK,因为它在js线程中运行,而不是在本机线程中运行
我发现了。它比firebase web SDK具有更高的性能,并且这个问题消失了这修复了黄色框和控制台日志。它甚至为世博会修复了它 只需将以下脚本放在代码库的开头
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);
}
};
从'react native'导入{YellowBox};
从“lodash”进口;
ignoreWarnings([“设置计时器]);
const_console=u.clone(console);
console.warn=消息=>{
如果(message.indexOf('Setting a timer')另一种方法是使用react native ignore warnings模块
这甚至适用于世博会应用程序
你可以用下面的方法
import ignoreWarnings from 'react-native-ignore-warnings';
ignoreWarnings('Setting a timer');
也可以在android上运行。在login()
中,您的设置超时()
调用缺少间隔值。一般来说,如果窗口/选项卡位于后台,浏览器现在不会触发超时/间隔,或者至少不会及时触发。这是为了防止滥用脚本行为,并减少可能正在轮询的脚本的功耗
原则上,您的代码应该可以工作,如果用户在计时器运行时离开窗口,那么当他们返回时,它将完成。从用户体验的角度来看,这可能是您想要的,因为用户看到的是转换,而不是在他们不看的情况下在后台发生的转换。这有助于他们保持心理环境。
黄色框是因为您根据消息设置了过长的计时器(近两分钟)这不太可能是你想要的。JS环境警告你,你正在做的事情不太可能是你想要的。如果你想要的话,你可以将警告静音。谷歌软件工程师Josh Crowther说:
但是,使用多步骤短持续时间设置超时实际上并不能解决问题。计时器模块仍然保持活动状态,应用程序仍然存在警告中指出的性能问题。这里的问题是,我们有需要长时间设置的用例,react native没有针对该用例进行优化
因此,所有这些都是:这个错误在这里无法修复,我们只能解决这个错误。有一些解决方法(请参阅)可以禁用警告。在我们的代码中禁用警告对问题没有帮助(除了禁用警告),并且添加了完全不必要的额外SDK代码/权重
如果您对提供的解决方案感到不舒服,我建议您就上述问题(即facebook/react native#12981)进行咨询。我认为解决此问题的最贴心的解决方案(直到RN内部解决此问题)是上述解决方案
//将此代码添加到项目中以重置所有超时
const highestTimeoutId=setTimeout(()=>“;”);
for(设i=0;i
在使用Firebase调用时,我仍然会收到一个黄色框警告(在settimeout上),但此后再也不会出现任何并发警告。我不确定在什么时候调用它可能会发生
// add this code to your project to reset all timeouts
const highestTimeoutId = setTimeout(() => ';');
for (let i = 0; i < highestTimeoutId; i++) {
clearTimeout(i);
}
import { YellowBox } from 'react-native';
construct() {
YellowBox.ignoreWarnings(['Setting a timer']);
}
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);
};
}
componentDidMount() { console.disableYellowBox = true; ... }
// Firebase App (the core Firebase SDK) is always required and
// must be listed before other Firebase SDKs
import * as firebase from "firebase/app";
import "firebase/auth";
import {LoginStatus} from "./LoginStatus";
import {auth, User} from "firebase";
import {ApiResponse, DelegateBearerAuthClient, HttpClient} from "@hardcodet/httpclient";
import {Env} from "../../Env";
export class FirebaseClient {
/**
* Creates a simple API client to use with Firestore.
* We don't want to use the JS package's implementation since it has issues with
* long-running timers - see https://github.com/firebase/firebase-js-sdk/issues/97
* @param idToken The user's ID token as retrieved through firebase auth
*/
private static getFirestoreClient(idToken: string) {
const projectId = Env.firebaseProjectId;
const baseUri = `https://firestore.googleapis.com/v1/projects/${projectId}/databases/(default)/documents/`
const authClient = new DelegateBearerAuthClient(async () => idToken);
return new HttpClient(baseUri, {authClient});
}
/**
* Use firebase auth for login etc. because lazy.
*/
public static async userLogin(email: string, password: string): Promise<User> {
try {
const credentials: firebase.auth.UserCredential = await auth().signInWithEmailAndPassword(email, password);
return credentials.user;
} catch (error) {
console.error(error);
return undefined;
}
}
private static resolveStatus(errorCode: string): { user: User, status: LoginStatus } {
switch (errorCode) {
case "auth/invalid-email":
return {user: undefined, status: LoginStatus.InvalidEmailAddress};
case "auth/user-not-found":
return {user: undefined, status: LoginStatus.UnknownUserId};
case "auth/wrong-password":
return {user: undefined, status: LoginStatus.WrongPassword};
case "auth/email-already-in-use":
return {user: undefined, status: LoginStatus.EmailAddressAlreadyInUse};
case "auth/weak-password":
return {user: undefined, status: LoginStatus.WeakPassword};
case "auth/user-disabled":
return {user: undefined, status: LoginStatus.UserDisabled};
case "auth/expired-action-code":
return {user: undefined, status: LoginStatus.InvalidActionCode};
default:
return {user: undefined, status: LoginStatus.Undefined};
}
}
/**
* Resolve the user's keys from the backend.
*/
public static async getSomeUserData(firebaseUserId: string, idToken: string): Promise<...> {
const client: HttpClient = FirebaseClient.getFirestoreClient(idToken);
// userData here is the name of my collection in firestore. i'm using the user ID as the document ID
var result = await client.getAs<any>(`userData/${firebaseUserId}?key=${Env.firebaseApiKey}`);
if (result.success) {
const json = result.value;
const foo = json.fields.foo.stringValue;
const bar = json.fields.bar.stringValue;
return ...
} else {
if (result.notFound) {
// that document with that key doesn't exist
console.warn("no document with key " + firebaseUserId);
return undefined;
}
throw result.createError();
}
}
public static async writeSomeData(idToken: string, firebaseUserId: string, foo: string, bar: string): Promise<...> {
const data = {
"fields": {
"foo": {
"stringValue": foo
},
"bar": {
"stringValue": bar
}
}
};
// again, just do an HTTP post, use the firebase user ID as the document key
const client: HttpClient = FirebaseClient.getFirestoreClient(idToken);
const result: ApiResponse = await client.post(`userData?documentId=${firebaseUserId}&key=${Env.firebaseApiKey}`, data);
if (result.success) {
return ...
} else {
throw result.createError();
}
}
/**
* Gets the currently logged in user, if any.
*/
public static getCurrentUser(): User {
return auth().currentUser;
}
public static async sendPasswordReset(email: string): Promise<LoginStatus> {
try {
await auth().sendPasswordResetEmail(email);
return LoginStatus.Success;
} catch (error) {
return FirebaseClient.resolveStatus(error.code).status;
}
}
/**
* Clears the current user from the session.
*/
public static async signOut() {
await auth().signOut();
}
}
const user: User = await FirebaseClient.userLogin("me@domain.com", "mypassword");
const idToken= await user.getIdToken(false);
const data = await FirebaseClient.getSomeUserData(user.uid, idToken);
import { YellowBox } from 'react-native';
YellowBox.ignoreWarnings(['Setting a timer']);
import { LogBox } from 'react-native';
LogBox.ignoreLogs(['Setting a timer']);
import { LogBox } from 'react-native';
LogBox.ignoreLogs(['Setting a timer for a long period of time'])
import { YellowBox } from 'react-native';
YellowBox.ignoreWarnings(['Setting a timer for a long period of time']);