长时间设定计时器,即多分钟

时间:2017-06-17 10:15:36

标签: javascript firebase react-native

我想使用firebase auth with {native LoginSignup,但我收到黄色错误:

长时间(即多分钟)设置计时器是Android上的性能和正确性问题,因为它使计时器模块保持唤醒状态,并且只有在应用程序位于前台时才能调用计时器。有关详细信息,请参阅(https://github.com/facebook/react-native/issues/12981)。 (看到setTimeout,持续时间为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>
            )
        }
    }

我向 Google Firebase小组报告:(https://github.com/firebase/firebase-js-sdk/issues/97

17 个答案:

答案 0 :(得分:9)

这会修复黄色框和控制台日志。它甚至为世博会确定了它。

只需将以下脚本放在代码库的开头即可。

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);
  }
};

答案 1 :(得分:6)

Google Say的Josh Crowther软件工程师:

使用多步短持续时间setTimeouts实际上并没有解决问题。定时器模块仍然保持活动状态,应用程序仍然会受到警告中指示的性能问题的影响。这里的问题是,我们的用例需要很长的计时器,而本地的反应并没有针对该用例进行优化。

所有这一切的网络:此错误无法解决,我们只能解决错误,有可用的解决方法(请参阅Setting a timer for a long period of time, i.e. multiple minutes)禁用警告。在我们的代码中执行禁用警告的工作,不会帮助解决问题(除了禁用警告之外),并添加完全没有必要的额外SDK代码/权重。

如果您对提供的解决方法感到不舒服,我建议您解决上述问题(即facebook / react-native#12981)

答案 2 :(得分:3)

如果您使用的是 react-native 0.63,请在您的 App.js 文件中执行以下操作: 从 react-native

导入 LogBox
import { LogBox } from 'react-native';

并且在您的 App.js 文件中的所有导入之后只添加这一行,没有必要在任何 useEffect 调用中添加这一行。

LogBox.ignoreLogs(['Setting a timer for a long period of time'])

请参阅 docs 了解更多信息。


如果您使用的是 react-native 0.62,请在您的 App.js 文件中执行以下操作: 从 react-native

导入 YellowBox
import { YellowBox } from 'react-native';

并且在您的 App.js 文件中的所有导入之后只添加这一行,没有必要在任何 useEffect 调用中添加这一行。

YellowBox.ignoreWarnings(['Setting a timer for a long period of time']);

请参阅 docs 了解更多信息。

答案 3 :(得分:3)

我所做的并且正在与我一起工作,但是不管是否是一种好的做法,我仍然不知道

导航到文件

node_modules \ react-native \ Libraries \ Core \ Timers \ JSTimers.js

有一个函数const MAX_TIMER_DURATION_MS = 60 * 1000,我将时间增加为60 * 100000,它停止出现了

答案 4 :(得分:2)

我遇到了同样的问题,我认为这是firebase web SDK的问题所以我决定放弃firebase web SDK,因为它运行在js线程中,而不是反应原生线程。

我找到了react-native-firebase。它比具有更高性能的firebase web SDK更好,这个问题消失了

答案 5 :(得分:2)

只需添加这两行

import { LogBox } from 'react-native';

LogBox.ignoreLogs(['Setting a timer']);

答案 6 :(得分:2)

我正在使用此代码禁用警告

import { YellowBox } from 'react-native';
YellowBox.ignoreWarnings(['Setting a timer']);

答案 7 :(得分:2)

对于Firebase / firestore用户:我没有尝试掩盖/隐藏警告,而是简单地恢复为REST API。就像魅力一样:)

  • 我正在使用firebase节点软件包进行身份验证
  • 我正在对Firestore使用常规的HTTP调用(它也摆脱了其他必要的atobbto黑客)

下面的代码段仅使用HTTP客户端(https://github.com/hardcodet/httpclient-js),您可以使用任何适合自己的功能(例如fetch或axios)。

// 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();
    }
}

请注意idToken参数-这只是您从firebase User类中获得的ID令牌:

        const user: User = await FirebaseClient.userLogin("me@domain.com", "mypassword");

        const idToken= await user.getIdToken(false);
        const data = await FirebaseClient.getSomeUserData(user.uid, idToken);

答案 8 :(得分:1)

另一种方法是使用react-native-ignore-warnings模块。

https://github.com/jamrizzi/react-native-ignore-warnings

https://www.npmjs.com/package/react-native-ignore-warnings

这甚至适用于Expo应用程序。

您可以通过以下方式使用它。 。

import ignoreWarnings from 'react-native-ignore-warnings';

ignoreWarnings('Setting a timer');

也可以用android运行..?

答案 9 :(得分:1)

login()中,您的setTimeout()来电缺少间隔值。作为一般情况,如果窗口/选项卡在后台,或者至少不期望它们是及时的,浏览器现在不会触发超时/间隔。这是为了防止滥用脚本行为,并减少可能轮询的脚本的功耗。

您的代码原则上应该工作,如果用户在计时器运行时切换窗口,它将在返回时完成。从UX的角度来看,这可能是您想要的,因为用户看到了转换,而不是在他们不看时在后台发生。它有助于他们保持心理背景。

黄色框是因为您根据消息(将近两分钟)设置了一个过长的计时器,并且这不太可能是您想要的上下文。 JS环境警告你,你正在做的事情不太可能是你想要的。如果符合您的要求,您可以将警告静音。

答案 10 :(得分:1)

我认为最有效的解决方案(直到RN内部修复)是here中提到的解决方案。

// add this code to your project to reset all timeouts
const highestTimeoutId = setTimeout(() => ';');
for (let i = 0; i < highestTimeoutId; i++) {
    clearTimeout(i); 
}

习惯了-针对Firebase调用,我仍然收到一个黄框警告(在settimeout上),但是此后再也不会出现任何并发警告。我不确定在此时调用此方法可能也不会触发唯一的警告,但是在Firebase的async调用之后不会再引发任何并发警告。

答案 11 :(得分:1)

要解决此问题...

  1. 导航到您的node_modules / react-native / Libraries / Core / Timers / JSTimers.js文件。

  2. 寻找变量MAX_TIMER_DURATION_MS

  3. 将其值更改为10000 * 1000

  4. 保存更改(关闭自动格式)并重新构建您的应用。

https://github.com/firebase/firebase-js-sdk/issues/97#issuecomment-485410026

上找到了这个答案

答案 12 :(得分:0)

这将忽略所有警告。

App.js

import { LogBox} from "react-native";
....

LogBox.ignoreAllLogs();

答案 13 :(得分:0)

在Expo中,它仅对我有用,该代码是我在相关的Github问题中从CopyJosh's answer获得的:


class App extends Component {
  constructor() {
    super();
    YellowBox.ignoreWarnings(['Setting a timer']);
    console.ignoredYellowBox = ['Setting a timer'];
    const consoleClone = clone(console);
    console.warn = message => {
      if (message.indexOf('Setting a timer') <= -1) {
        consoleClone.warn(message);
      }
    };
  }

  render() {
    return (...);
  }
}

export default App;

关键是将代码放在App入口点constructor函数中。

答案 14 :(得分:0)

面对同样的问题。似乎,我们暂时不得不隐藏警告。这是最简单的方法:

componentDidMount() { console.disableYellowBox = true; ... }

答案 15 :(得分:0)

解决带有黄色警告“设置计时器”的问题。

(尽可能快地复制并导入以下文件;-))

void OnTriggerStay2D(Collider2D other)
{
    if (Input.GetKeyDown(interactableKey))
    {
        chestInventoryUI.SetActive(true);
        Time.timeScale = 0.0f;
    }

    if (Input.GetKeyUp(interactableKey))
    {
        chestInventoryUI.SetActive(false);
        Time.timeScale = 1.0f;
    }
}

答案 16 :(得分:0)

import { YellowBox } from 'react-native';

construct() {
    YellowBox.ignoreWarnings(['Setting a timer']);
}

这忽略了对我的警告。您应该将其添加到显示警告的每个页面的构造函数中。

忽略它不是最好的方法,但是如果您使用的是Firebase Realtime Database。 They are looking与其图书馆一起解决此问题,即使该问题已有2年之久了。