React-native: Добавьте поддержку AlarmManager в Timing, чтобы обеспечить правильную обработку длительных таймеров

Созданный на 16 мар. 2017  ·  173Комментарии  ·  Источник: facebook/react-native

Установка таймеров на несколько минут не обрабатывается должным образом в React Native на Android: он держит модуль Timing активным вместо того, чтобы полагаться на то, что система разбудит нас, когда таймер должен сработать.

Мы должны изучить установку отсечки, при которой мы делегируем AlarmManager и Handler.postDelayed вместо того, чтобы обрабатывать таймеры с помощью framecallbacks.

Bug JavaScript Android

Самый полезный комментарий

@ skv-headless Мнение поступает. :)

На мой взгляд, нужно избавиться от такого отношения к проблемам. Я видел, как это всплывает все чаще и заставляет людей игнорировать предупреждения. Это предупреждения. Они вас предупреждают. Не игнорируйте их, сделайте что-нибудь. Я видел приложения, в которых игнорировались все предупреждения, даже уведомления об устаревании. Затем ваше приложение ломается, и вы не знаете, почему.

В этом случае вы можете настроить эти таймауты и уменьшить их или настроить другой подход к ним. Может быть, даже ткните к разработчикам библиотек и попросите их помочь найти решение.

Я советую следовать этой теме, пока кто-то умный не найдет реальное решение, чтобы вы могли затем научиться этому ответу. А потом, может быть, тем временем (если вы не можете / не хотите решать проблему) игнорируйте предупреждения.

TL; DR;

Да, вы можете временно игнорировать предупреждения. Просто проверяйте время от времени, чтобы узнать, каков статус и требуются ли какие-либо действия.

Все 173 Комментарий

Отличное улучшение!

это поможет с socket.io, который по умолчанию держит таймер 85000ms . На мастере RN порог равен 60000ms .

И Firebase, который также использует долгие таймеры.

Я получаю следующее предупреждение при использовании библиотеки firebase

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)

Как избавиться от этого предупреждения ...

Я получаю следующее предупреждение при использовании библиотеки firebase. Кто-нибудь знает, как решить эту проблему?

Я также получаю это предупреждение с помощью firebase.

"firebase": "^3.9.0",
"react-native": "0.44.0"

Та же проблема ( 85000ms ), но без firebase . Мой список пакетов:

  "dependencies": {
    "apisauce": "0.11.0",
    "format-json": "1.0.3",
    "lodash": "4.17.4",
    "markdown-it": "^8.3.1",
    "native-base": "^2.1.3",
    "normalizr": "^3.2.2",
    "prop-types": "^15.5.10",
    "querystringify": "1.0.0",
    "ramda": "0.23.0",
    "react": "16.0.0-alpha.6",
    "react-markdown": "^2.5.0",
    "react-native": "0.44.0",
    "react-native-animatable": "1.2.0",
    "react-native-config": "0.4.2",
    "react-native-device-info": "0.10.2",
    "react-native-drawer": "2.3.0",
    "react-native-htmlview": "0.9.0",
    "react-native-i18n": "1.0.0",
    "react-native-linear-gradient": "^2.0.0",
    "react-native-photo-view": "^1.2.0",
    "react-native-router-flux": "3.39.1",
    "react-native-scrollable-tab-view": "*",
    "react-native-share": "^1.0.20",
    "react-native-vector-icons": "4.1.1",
    "react-navigation": "^1.0.0-beta.9",
    "react-redux": "5.0.4",
    "redux": "3.6.0",
    "redux-persist": "4.6.0",
    "redux-saga": "0.15.3",
    "reduxsauce": "0.4.1",
    "seamless-immutable": "7.1.2"
  },
  "devDependencies": {
    "ava": "^0.18.2",
    "babel-eslint": "^7.1.1",
    "babel-preset-es2015": "^6.18.0",
    "enzyme": "^2.6.0",
    "husky": "^0.13.1",
    "ignite-animatable": "^0.3.1",
    "ignite-dev-screens": "^2.0.0-beta.9",
    "ignite-i18n": "^0.1.1",
    "ignite-ir-boilerplate-2016": "^0.2.2",
    "ignite-vector-icons": "^0.2.1",
    "mockery": "^2.0.0",
    "nyc": "^10.1.2",
    "react-addons-test-utils": "^15.3.1",
    "react-dom": "^15.4.0",
    "react-native-mock": "^0.3.1",
    "reactotron-apisauce": "^1.7.0",
    "reactotron-react-native": "^1.7.0",
    "reactotron-redux": "^1.7.0",
    "reactotron-redux-saga": "^1.7.0",
    "snazzy": "^6.0.0",
    "standard": "^8.6.0"
  }

У меня аналогичная проблема при использовании версии 0.44.0 на Android. Я тоже не использую firebase:

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 85000ms)

Привет, ребята ... было интересно, есть ли какое-нибудь быстрое решение для этого. Я использую:

react-native 0.44 react 16.0.0-alpha.6 feathers-socketio 1.6.0

Это очень раздражает, когда я разрабатываю ... Могу ли я пока скрыть предупреждение ??

Такая же проблема здесь с firebase 3.9.0

Если это беспокоит, просто добавьте console.ignoredYellowBox = ['Setting a timer'];

@ skv-headless Мнение поступает. :)

На мой взгляд, нужно избавиться от такого отношения к проблемам. Я видел, как это всплывает все чаще и заставляет людей игнорировать предупреждения. Это предупреждения. Они вас предупреждают. Не игнорируйте их, сделайте что-нибудь. Я видел приложения, в которых игнорировались все предупреждения, даже уведомления об устаревании. Затем ваше приложение ломается, и вы не знаете, почему.

В этом случае вы можете настроить эти таймауты и уменьшить их или настроить другой подход к ним. Может быть, даже ткните к разработчикам библиотек и попросите их помочь найти решение.

Я советую следовать этой теме, пока кто-то умный не найдет реальное решение, чтобы вы могли затем научиться этому ответу. А потом, может быть, тем временем (если вы не можете / не хотите решать проблему) игнорируйте предупреждения.

TL; DR;

Да, вы можете временно игнорировать предупреждения. Просто проверяйте время от времени, чтобы узнать, каков статус и требуются ли какие-либо действия.

@imamatory, я думаю, принадлежит Rectotron

Я думаю, это Rectotron

В таком случае это предупреждение можно просто проигнорировать.
... однако мой эмулятор Android иногда замедляется, возможно, это одна из причин.

@imamatory Я надеюсь, что настоящее решение так же просто

Привет, думаю, я нашел решение:
Сначала вам нужно найти в своем проекте следующий файл: libraries / Core / Timers / JSTimer; js
Откройте его, и вам просто нужно изменить эту константу MAX_TIMER_DURATION_MS, чтобы увеличить продолжительность, превышающую вашу продолжительность, написанную в конце предупреждения!

@nicolasZZ привет, Спасибо за решение. но это хорошая практика - изменять библиотеку JSTimer а не наш собственный код?

@nicolasZZ @AmroAly На мой взгляд, это решение не является хорошей практикой, потому что оно очень нестабильно. Лучше всего игнорировать предупреждение, пока будет выпущено официальное решение.

console.ignoredYellowBox = [
    'Setting a timer'
]

решение @ skv-headless хорошее, но в моем случае работает только с "вводом" между скобками

@rigobcastro Спасибо, что скрывает назойливые предупреждения.

@ DZuz14 было бы здорово, если бы вы могли послать пиар или хотя бы начать разговор. Спасибо 👍

привет ~
Я использовал socket.io. nodejs and RN44 or RN 45
Я видел предупреждение этого таймера.

Я нашел это решение
reference reactotron PR

персональный сервер nodejs и scoket.io

const express = require('express')
const app = express()
const server = require('http').Server(app)
const io = require('socket.io')(server, {pingTimeout: 30000})

Благодаря!

У меня есть простой собственный проект реакции для Android, и я использую аутентификацию firebase с исходной реакцией для входа и регистрации, но у меня возникла эта желтая ошибка. Что мне делать? Ссылка на мой вопрос в stackoverslow (https://stackoverflow.com/questions/44603362/setting-a-timer-for-a-long-period-of-time-ie-multiple-minutes)

Спасибо @ DZuz14
Я получаю эту ошибку при запуске react-native run-android

D:\Projects 2016\Web\Android\mohajerkade-android\android\app\src\main\java\com\mohajerkade\AlarmManagerModule.java:40: error: cannot find symbol
       Intent intent = new Intent(context, AlarmReceiver.class);
                                           ^
  symbol:   class AlarmReceiver
  location: class AlarmManagerModule
1 error
:app:compileDebugJavaWithJavac FAILED

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':app:compileDebugJavaWithJavac'.
> Compilation failed; see the compiler error output for details.

Я хочу использовать аутентификацию firebase с нативной реакцией для входа и регистрации, но я получил эту желтую ошибку,
1: Что конкретно представляет собой этот модуль?
2: Зачем моему проекту нужен этот модуль?

Я спросил stackoverflow по этой ссылке: (https://stackoverflow.com/questions/44603362/setting-a-timer-for-a-long-period-of-time-ie-multiple-minutes)
Я сообщил команде Google Firebase по этой ссылке: (https://github.com/firebase/firebase-js-sdk/issues/97)

@ DZuz14 У меня тот же вопрос, что и у @saeedhei .

В основном мы используем модуль firebase node, который использует эти таймеры с длительным периодом.

Я думаю, что добавления вашего модуля недостаточно, нам действительно нужно переписать код в модуле firebase node, чтобы использовать ваши будильники, а не таймеры Javascript, верно?

Спасибо @ DZuz14

Итак, если вы посмотрите на пакет npm под названием firebase вы обнаружите, что он использует setTimeout во многих местах. Это нормально, поскольку библиотека была написана для веб-сайтов и серверов node.js. react-native - это своего рода сервер node.js, но он работает на телефоне - и, как правильно указывает предупреждение, длительные таймеры Javascript не подходят в этой среде и могут разряжать аккумулятор и иметь другие нежелательные побочные эффекты .

Так что, я думаю, нам нужно убедить ребят из Firebase изменить ваш подход и распространить пакет, созданный специально для react-native .

@BerndWessels https://www.npmjs.com/package/react-native-firebase Вы это видели ? Говорит, что позволяет firebase работать в собственном потоке. Не уверен, насколько это правда, но, возможно, стоит взглянуть. Возможно, вы даже используете это, я не уверен.

@ DZuz14 Спасибо, я проверю.

console.ignoredYellowBox = [
'Установка таймера'
]

@rigobcastro Где я могу ввести или вставить этот код?

@ Jazz747 В верхней части установочного файла, например app.js, index.android.js или index.ios.js

console.ignoredYellowBox = [ 'Setting a timer' ]
Этот код только скрывает предупреждение внутри react native.

Как насчет предупреждения в консоли браузера?

Кто-нибудь знает, работает ли кто-нибудь из команды RN или сообщества над решением этой проблемы?

Всплывающее окно с предупреждением перенаправляет на эту проблему, но я не могу найти здесь подходящего решения, кроме как скрыть предупреждение, которое вообще не является решением. Есть идеи или предложения?

@SuhairZain Все, кажется, указывает на то, что это ошибки внешних библиотек для RN

@rigobcastro Это предупреждение можно легко воспроизвести с помощью вызова setInterval() с достаточно большим временем (в моем случае это было 5 минут). Поэтому я бы сказал, что это не вызвано сторонними библиотеками.

Кстати, с тех пор я нашел здесь библиотеку: response-native-background-timer, которая помогает мне выполнять работу.

@SuhairZain да setInterval() ), и предупреждение исчезло.

Хорошая рекомендация, спасибо.

у меня такая же проблема. И все же я могу понять, как мне справиться с этой проблемой.

рН: 0,45,1
firebase: 4.1.3

Уважаемый @escalepion, я сообщил команде

@escalepion Если ваша проблема

@SuhairZain, извините, я могу понять, как можно использовать setInterval или response-native-background-timer :( где и как я буду писать код? У вас есть пример?

У кого-нибудь есть подсказка, как выяснить, какая библиотека причиняет вред? Я недавно обновил RN до 0.46, и внезапно появилась эта ошибка. В моем проекте довольно много библиотек, и я могу думать только об их исследовании по одной, что явно не идеально.

Ура!

@ abeltje1 , если вы

@liketurbo точно буду

У меня есть эта проблема вместе с redux-saga для повторной проверки токена API каждые 30 минут.

Следовательно, в этом случае ожидание так долго действительно правильно. И я предполагаю, что есть и другие сценарии, которые ожидаются долгое ожидание.

Тогда у меня вопрос: почему это предупреждение? Что может сломаться / случиться? Разве я не должен иметь возможность использовать какие-либо LLT (долгоживущие транзакции)?

Если LLT в порядке. Как лучше всего решить эту проблему? Расширяете время AlarmManager?

Заранее спасибо ;)

У меня та же проблема, что и у @sospedra. Я использую redux-saga и у меня есть сага, которая обновляет некоторые данные в приложении в фоновом режиме каждые 3 минуты, поэтому сага включает код yield call(delay, 3 * 60000); . В результате получаю ошибку «Установка таймера на длительный период времени ...».

Мне также интересно, каков предлагаемый подход для чего-то вроде этого. С какими проблемами я столкнусь, если просто оставлю свой код работающим таким образом. Сообщение об ошибке означает, что могут быть проблемы с производительностью и, возможно, таймер не сработает в нужное время, если приложение работает в фоновом режиме?

Если с этим кодом, устанавливающим таймер на 3 минуты, вероятно возникнут проблемы, какое альтернативное решение обеспечит такую ​​же функциональность и не столкнется с этими проблемами?

все еще возникает такая же проблема.

Я думаю, единственное решение - перейти на Native Android Development.

Проблема все еще не может быть решена? Кто-нибудь нашел решение?

Я получаю предупреждение при использовании firebase.

Если проблема не в сторонней библиотеке, а в том, что вы сами установили длительный тайм-аут, хорошим решением будет использование библиотеки response-native-background-timer . README также содержит простой пример.

К сожалению , если проблема связана с сторонней библиотекой, у вас, вероятно, нет другого решения, кроме как найти место, где вызывается setTimeout, и поднять проблему / отправить PR, чтобы вместо этого использовать вышеупомянутую библиотеку , попробуйте мое возможное решение ниже на https://github.com/facebook/react-native/issues/12981#issuecomment -331074444 и попробуйте, работает ли это для вас.

Пожалуйста, сделайте отличный тайм-аут и на Android.

React-native-background-timer - хорошее обходное решение, как сказал @SuhairZain . это может очистить предупреждающее сообщение

Я получаю это предупреждение при использовании socket.io

потому что socket.io имеет таймер 85 мс

FWIW это происходит со мной только когда я использую Reactotron во время разработки ...

Должен признаться, на время сводил меня с ума, но я знал, что не могу проигнорировать сообщение

Я больше не работаю над проектом, с которым у меня возникла эта проблема, поэтому я не могу проверить, работает ли этот подход, но он должен, по крайней мере, теоретически. Если ошибка связана с модулем стороннего производителя, использующим setTimeout или setInterval с большой задержкой, это должно помочь решить вашу проблему. Что он делает, так это обезьяна исправляет глобальные setTimeout и setInterval, чтобы вместо этого использовать response-native-background-timer :

import BackgroundTimer from 'react-native-background-timer';

setTimeout = BackgroundTimer.setTimeout;
setInterval = BackgroundTimer.setInterval;
clearTimeout = BackgroundTimer.clearTimeout;
clearInterval = BackgroundTimer.clearInterval;

Напишите этот код где-нибудь при начальной инициализации, желательно index.android.js или index.ios.js как можно раньше. Если кто-то сможет это проверить, мы будем очень признательны.

@SuhairZain : ваше предложение пока работает для меня, с некоторыми изменениями:

setTimeout = BackgroundTimer.setTimeout.bind(BackgroundTimer)
setInterval = BackgroundTimer.setInterval.bind(BackgroundTimer)
clearTimeout = BackgroundTimer.clearTimeout.bind(BackgroundTimer)
clearInterval = BackgroundTimer.clearInterval.bind(BackgroundTimer)

@levity Я добавил ваш код в свой app.js, но у меня есть это

undefined не является объектом (оценка RNBackgroundTimer.setTimeout)

@realtebo звучит так, будто вы, возможно, не завершили установку react-native link или используя CocoaPods.

@levity : вы имеете в виду запускать react-native link ?

npm install -g react-native-cli
реакция на родную ссылку
Сканирование папок на наличие символических ссылок в C: \ Users \ realtebo \ Downloads \ manager2 \ node_modules (54 мс)
react-native link нельзя использовать в проектах Create React Native App. Если вам нужно включить библиотеку, основанную на собственном собственном коде, вам, возможно, придется сначала извлечь. См. Https://github.com/react-community/create-react-native-app/blob/master/EJECTING.md для получения дополнительной информации.

Я не хочу катапультироваться .... итак, .. что я могу сделать?

Ой, извините, я не знаю, как помочь вам с проектом Create React Native App. Сам я этим никогда не пользовался.

Всем привет,
У меня проблемы с react-native: ^0.49.3 ...

ср. https://github.com/ocetnik/react-native-background-timer/issues/65

Надеюсь, ты сможешь помочь, спасибо за уделенное время;)

Привет, у меня такая же проблема, как и при использовании 0.49 , она появилась после этого

export function saveUserData(userInfo){
  return (dispatch) => {
    dispatch(saveDataRequest())
    const userId = firebase.auth().currentUser.uid;
    return firebase.database().ref('users/' + userId).set(userInfo)
      .then(() => {
        dispatch(saveDataSuccess());
        dispatch(NavigationActions.navigate({ routeName: 'TabContactNavigation' }))
      })
      .catch((error) => {
        dispatch(saveDataFailure(error))
      });
  }
}

Выше указано Action в сокращении, которое также использует redux-thunk .. Когда кнопка нажата для сохранения данных из формы в firebase при успешном сохранении отправляется saveDataSuccess() а затем перейдите на следующую вкладку.
Теперь я подозреваю, что проблема здесь const userId = firebase.auth().currentUser.uid но я не уверен. Вот скриншот проблемы. (приложение работает нормально, но появляется это предупреждение, я не знаю, следует ли мне просто игнорировать его) или, может быть, я здесь что-то делаю не так, нужна ваша помощь, ребята, спасибо

warning

warning2

Эй, предупреждение касается setTimeout, вы используете его в своем компоненте?
и да, строка const userId = firebase.auth (). currentUser.uid; не работает, это обещание, и когда вы используете userId, он все еще не приходит.
лучший способ сделать это - получить userId от actionCreator, вы уже отправляете переменную userInfo, попробуйте следующее:

Я предполагаю, что информация о пользователе исходит из входа в firebase auth, поэтому у вас есть uid

функция экспорта saveUserData (userInfo) {
return (отправка) => {
отправка (saveDataRequest ())
// const userId = firebase.auth (). currentUser.uid;
вернуть firebase.database (). ref ('users /' + userInfo.uid) .set (userInfo)
.then (() => {
отправка (saveDataSuccess ());
отправка (NavigationActions.navigate ({routeName: 'TabContactNavigation'}))
})
.catch ((ошибка) => {
отправка (saveDataFailure (ошибка))
});
}
}
я надеюсь, что это может помочь, и извините за мой плохой английский = P

BlisS

23.10.2017, 23:59, Yasir [email protected] escribió:

Привет, у меня та же проблема, что и я использую 0.49, она появилась после этого

функция экспорта saveUserData (userInfo) {
return (отправка) => {
отправка (saveDataRequest ())
const userId = firebase.auth (). currentUser.uid;
вернуть firebase.database (). ref ('users /' + userId) .set (userInfo)
.then (() => {
отправка (saveDataSuccess ());
отправка (NavigationActions.navigate ({routeName: 'TabContactNavigation'}))
})
.catch ((ошибка) => {
отправка (saveDataFailure (ошибка))
});
}
}
Вышеупомянутое действие в redux, которое также использует redux-thunk. Когда нажимается кнопка для сохранения данных из формы в firebase, при успешном сохранении она отправляет saveDataSuccess (), а затем переходит на следующую вкладку.
Теперь я подозреваю, что проблема здесь: const userId = firebase.auth (). CurrentUser.uid, но я не уверен. Вот скриншот проблемы. (приложение работает нормально, но появляется это предупреждение, я не знаю, следует ли мне просто игнорировать его) или, может быть, я здесь что-то делаю не так, нужна ваша помощь, ребята, спасибо

https://user-images.githubusercontent.com/12644122/31925375-94b7c464-b89d-11e7-889d-e9d00866ff73.png
https://user-images.githubusercontent.com/12644122/31925386-9e9bf3c4-b89d-11e7-9eaa-65147879629f.png
-
Вы получаете это, потому что подписаны на эту ветку.
Ответьте на это письмо напрямую, просмотрите его на GitHub https://github.com/facebook/react-native/issues/12981#issuecomment-338874018 или отключите поток https://github.com/notifications/unsubscribe-auth/ AHhM1oYWKrWSOZsm-8hjp4Q6qJSfqraUks5svW6-gaJpZM4Mf0Z0 .

Обычно я сохраняю userinfo в хранилище redux.
Поэтому я просто повторно использую по мере необходимости.
... но ... в аналогичной ситуации у меня такая же проблема с таймаутом

Та же проблема с библиотекой react-native-signalr (300000 мс)

Параметры сервера socket.io
pingTimeout (60000) + pingInterval (25000) <= 60000

Есть какие-нибудь новости о том, как с этим бороться на Android? Все еще получаю, не используя setTimeout ...

Просто чтобы продолжить мой предыдущий комментарий (от августа), который, как я полагаю, суммирует чувства всех людей здесь: мы в порядке с этой штукой с AlarmManager, просто мы хотим знать лучший подход для обработки долгоживущих транзакций

коп @shergin @cpojer @javache @hramos

Исправление для response-native-signalr (ms-signalr-client) на Android - переопределить pinginterval по умолчанию (300000):
connection.start({ pingInterval: 5000, jsonp: true, transport: ['webSockets', 'serverSentEvents', 'longPolling']}).done(() => { console.log('Now connected, connection ID =' + connection.id) })

Та же проблема с response-native-pomelo (80000 мс)

console.ignoredYellowBox = ['Setting a timer'];

Это вполне безопасно в качестве обходного пути, так как вы все равно будете получать предупреждение в консоли Chrome при удаленной отладке.

Где именно лучше всего разместить код игнорирования консоли? '

- nevermind, получил подсказку от связанного stackexchange , добавленного в мой App.js следующим образом:

class App extends Component {
  constructor() {
    super();

    console.ignoredYellowBox = [
      'Setting a timer'
    ];
  }
...
}
````

and also tried in my index.js as <strong i="8">@haikyuu</strong> just recommended..

импортировать {AppRegistry} из 'react-native';
импортировать приложение из './App';

console.ignoredYellowBox = [
'Установка таймера'
];

AppRegistry.registerComponent ('менеджер', () => Приложение);
`` ''

работал в обоих

@CopyJosh, вы можете поместить его в свой входной файл: index.js

так что пока нет реального решения этого вопроса? прошло уже 8+ месяцев ..

?

Давайте тогда решим эту проблему. Вероятно, нам придется выяснить:

A.) Простой расширяемый API, который можно вызывать через код React. Я думаю, что было бы разумно заняться, возможно, тем, чтобы заставить работать хотя бы один из методов AlarmManager. Например, вызов следующего метода в вашем коде React Native установит сигнал тревоги с помощью собственного AlarmManager устройств Android.
AlarmMgr.setInexactRepeating(arg1, arg2...)

Б.) Фактическая реализация, чтобы заставить это работать. Насколько мне известно, установка будильника с помощью AlarmManager отправляет так называемое «ожидающее намерение» в службу AlarmManager. Вы говорите AlarmManager, что хотите выполнить некоторую «задачу» в будущем. Мне кажется, что вам нужно, чтобы AlarmManager (или пользовательский Java-метод React) отправлял некоторый тип данных обратно в ваш код JavaScript, сообщая ему, какой код выполнять после срабатывания будильника.

Кто-нибудь готов заняться этой проблемой? Больше можно прочитать о AlarmManager здесь .

Кстати, эта неэффективность (связанная с длительными многоминутными таймаутами) является новой проблемой только для версий RN> 0.43? Или просто предупреждение выплевывается от RN> 0,43? Я перешел с 0.43.x на 0.47.x и начал видеть предупреждение. Я предположил, что неэффективность была всегда, и что RN только начал предупреждать меня об этом сейчас ..

однако с момента миграции несколько дней назад я также заметил, что мое приложение потребляет намного больше батареи на моем телефоне! (и другие особенности в различии не являются очевидными виновниками)

Привет, @astreet , возможно, вы все еще помните, о чем вы имели в виду, когда публикуете эту проблему и добавляете это предупреждение здесь https://github.com/facebook/react-native/commit/3637bce479 ?

Недавно это стало меня очень раздражать после того, как я начал использовать одну библиотеку, которая устанавливает 2-минутный повторяющийся таймер, поэтому я начал копаться в ней, чтобы понять, почему это предупреждение было добавлено в первую очередь.

Теперь меня беспокоит это предложение: «не дает спящему модулю синхронизации». Я думаю, вы, возможно, имеете в виду, что модуль Timer устанавливает обратный вызов хореографа. Хотя обратный вызов вроде бы установлен независимо от того, есть у нас таймер или нет. См. Соответствующую часть кода здесь: https://github.com/facebook/react-native/blob/1e8f3b11027fe0a7514b4fc97d0798d3c64bc895/ReactAndroid/src/main/java/com/facebook/react/modules/core/Timing.java#L106
Нет кода для остановки обратного вызова, когда нет запланированных таймеров и нет кода для запуска планирования при добавлении таймера. Обратный вызов приостанавливается только тогда, когда приложение переходит в фоновый режим, и восстанавливается при возврате на передний план.

Как следствие, обратный вызов хореографа ставится в очередь для каждого кадра независимо от того, установлен ли у нас таймер на длительный период, короткий период или вообще не установлен. Я не понимаю, как установка длительного таймера может повлиять на производительность в этом случае. Значит ли это, что в предупреждении нет необходимости?

Что касается установки длинного таймера как «проблемы с правильностью», я думаю, вы имеете в виду тот факт, что таймеры будут вызываться только в состоянии переднего плана приложения (поэтому, когда вы устанавливаете его на некоторое время в будущем, и приложение переходит в режим bg он либо не будет выполняться, либо будет выполнен, когда приложение перейдет на передний план, что может быть значительно позже, чем вы ожидали). Хотя я считаю, что это тот же случай для iOS, где мы не показываем предупреждение

В socket.io цикл ping по умолчанию составляет 85000 мс, = pingInterval (25000 мс) + pingTimeout (60000 мс). и вы должны сбросить эти параметры на сервере и убедиться, что сумма pingInterval и pingTimeout <= 60000 мс.

например:

var socket = require('socket.io')(12345, {
  pingInterval: 20000, 
  pingTimeout: 40000
})

Просто любопытно - мне нужно установить в моем приложении тайм-аут примерно 5 минут. Насколько серьезна эта проблема и насколько она повлияет на меня?

@ntomallen Если приложение будет все время на экране, то ничего не изменится. Будет работать гладко. В противном случае, возможно, он не сработает по истечении 5 минут. Или сойдет не совсем точно.

Я использую laravel echo с React Native для изменения параметров сервера сокета Android pingTimeout на 30000. Это работает

@sospedra gotcha . Придется провести небольшое тестирование, чтобы убедиться, что это не так уж плохо!

Есть ли причина не всегда использовать Handler.postDelayed?

какое-нибудь быстрое решение этой проблемы? Я только начал использовать RN с Firebase.

Я пробовал несколько разных решений для таймера, но мне так и не удалось заставить работать в фоновом режиме (постоянно).

Я использую setInterval для проверки связи с моим сервером каждые 10 минут - я только что заметил это сообщение об ошибке, потому что я делаю setInterval(myFunction, 60000) . Это то, о чем мне нужно беспокоиться?

Мое ожидаемое поведение заключается в том, что пока приложение открыто, оно может отправлять запросы, но после того, как приложение приостановлено (нажатие одной кнопки «Домой»), запросы должны перестать срабатывать. Могу ли я ожидать такого поведения, и повлияет ли время автономной работы на время приостановки приложения?

Здесь не о чем беспокоиться, и предупреждение неверное, и его следует удалить. Нет «Модуля синхронизации», чтобы не заснуть, есть только обратный вызов Choreographer, который проверяет таймеры каждый кадр (что также делает минимальную детализацию для таймеров ~ 16 мс).

Существует проблема корректности в том смысле, что таймеры не срабатывают в фоновом режиме ни на iOS, ни на Android. Это предупреждение, похоже, относится именно к Android и не является точным. Все таймеры должны в конечном итоге сработать, когда приложение вернется на передний план.

Есть ли планы на ближайшее время решить эту проблему? Журнал раздражает каждый раз, когда мы тестируем на телефонах Android.

Моя проблема…

Я получал эту ошибку, потому что мой тайм-аут составлял ~ 59 минут. Код для вызова метода в начале часа и setTimeout для создания setInterval в начале следующего часа.

Мое решение…

  1. обновите setTimeout чтобы setInterval начинались в верхней части минуты.
  2. обновить функцию, вызываемую setInterval, чтобы она запускалась только в том случае, если текущие минуты были 0 .

Эта функция теперь запускается каждую минуту, а не каждый час ... но, поскольку она ничего не делает в 59 случаях из 60, кажется безвредной.

эй @beausmith , это действительно решение просто установить 60 таймеров? Насколько я понимаю, он по-прежнему сохраняет активность timerModule в течение того же часа, но не отображает предупреждение :)

@newah - да, это немного взломано ... можешь предложить лучшее решение?

@beausmith , я пробовал использовать https://github.com/ocetnik/react-native-background-timer, который использует собственные таймеры, что звучит как решение - я просто перезаписал setTimout и setInterval с этой реализацией библиотеки.

Поддержка таймеров в фоновом режиме может быть плюсом или минусом в зависимости от ваших потребностей :))

Вроде работает нормально, но мои проблемы не решились :)

У меня такое же предупреждение, если я использую response-intl FormattedRelative. Поскольку внутри компонента FormattedRelative используется таймер:

scheduleNextUpdate(props, state) {
    // Cancel and pending update because we're scheduling a new update.
    clearTimeout(this._timer);

    const {value, units, updateInterval} = props;
    const time = new Date(value).getTime();

    // If the `updateInterval` is falsy, including `0` or we don't have a
    // valid date, then auto updates have been turned off, so we bail and
    // skip scheduling an update.
    if (!updateInterval || !isFinite(time)) {
      return;
    }

    const delta = time - state.now;
    const unitDelay = getUnitDelay(units || selectUnits(delta));
    const unitRemainder = Math.abs(delta % unitDelay);

    // We want the largest possible timer delay which will still display
    // accurate information while reducing unnecessary re-renders. The delay
    // should be until the next "interesting" moment, like a tick from
    // "1 minute ago" to "2 minutes ago" when the delta is 120,000ms.
    const delay =
      delta < 0
        ? Math.max(updateInterval, unitDelay - unitRemainder)
        : Math.max(updateInterval, unitRemainder);

    this._timer = setTimeout(() => {
      this.setState({now: this.context.intl.now()});
    }, delay);
  }

Вот пример использования в моем коде:

<FormattedRelative value={date}>
    {(message: string) => <Text>{message}</Text>}
</FormattedRelative>

Кто-нибудь знает, как исправить это предупреждение?

Это все еще проблема. Это особенно раздражает при использовании сервисов firebase на android. Пожалуйста исправьте.

Это действительно плохая ошибка для служб firebase и когда вы зависите от сторонних приложений. Потому что firebase не работает, если вы переключаетесь между приложениями, чтобы что-то проверить, чтобы продолжить процесс.

Например, мы используем стороннюю / факторную систему входа в систему и используем firebase для перемещения токенов. Но поскольку мы очищаем, токен уходит до того, как человек вернется в наше приложение. Так что я могу изменить механизм очистки, или вы, ребята, можете исправить эту ошибку.

@vongohren не то, чтобы я полностью понимаю ваш вариант использования, но одна стратегия обхода может заключаться в том, чтобы сохранить дату фонового режима в вашем приложении при входе в фоновый режим, а затем при возврате на передний план сравните текущую дату с сохраненной датой фонового режима и выполните некоторую очистку если истек определенный период времени ...

Чтобы подробнее рассказать о моем варианте использования. Скажем, вы зависите от того, чтобы сказать «да» в другом приложении, чтобы принять логин. Feks переключается на приложение facebook, чтобы ответить утвердительно на запрос входа в систему от третьего лица. Конкретный пример, с которым я работаю, - это uPort, https://www.uport.me/. Затем, когда мы полагаемся на способ отправить сообщение нашему приложению, теперь в фоновом режиме, чтобы сказать, что все в порядке, это не работает с firebase, если мы не воспользуемся вашим подходом для очистки в более поздний момент.

Думаю, я просто зациклился на том, что очистка может произойти сразу после отправки информации, потому что тогда информация уже была отправлена, и она нам не понадобится. Но почему так получается, что подход firebase не работает в react native? Это останавливает своих фоновых рабочих.

Мне нужен 30-минутный тайм-аут в моем приложении. Каждый раз, когда пользователь взаимодействует с экраном, он сбрасывается (отбрасывать старый тайм-аут, создавать новый).

Любая альтернатива тому, как это сделать правильно? Не лучше ли справиться с этим с помощью нативного кода и передать что-нибудь в React по завершении?

вау, это все еще проблема

@nbennink проверьте ответ здесь . В настоящее время нет гарантированного способа запустить задачу в фоновом режиме, поскольку в игре задействовано несколько факторов (экономия заряда батареи, взаимодействие с пользователем и т. Д.).

Я также получаю такое же предупреждение после использования socket.io.
Предупреждение ниже:

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 85000ms)

Детали моего пакета ниже:

  • "реагировать": "^ 16.3.0-alpha.1",
  • "react-native": "0.54.4",
  • "socket.io": "^ 2.1.1",
  • "socket.io-client": "^ 2.1.1",

Найдите какое-нибудь постоянное решение?

Я также получаю такое же предупреждение после использования socket.io.
Предупреждение ниже:

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 85000ms)

Детали моего пакета ниже:

"реагировать": "^ 16.3.0-alpha.1",
"react-native": "0.54.4",
"socket.io": "^ 2.1.1",
"socket.io-client": "^ 2.1.1",

Найдите какое-нибудь постоянное решение?

То же самое, нет возможности обойти это?

Это предупреждение по-прежнему появляется на response-native 0.57, должна ли быть открыта эта проблема?

Почти год и React Native все еще имеют ту же проблему !!!

Столкнувшись с одной и той же проблемой, одно и то же предупреждение появляется 3-4 раза. Очень назойливый.

Есть какое-то решение этой проблемы?

Избавился от предупреждающего сообщения этим решением https://stackoverflow.com/a/48778011/7427111

Я думаю, это просто скрытие сообщения, а не устранение проблемы.

@dhavaljardosh Да, ваше предположение верно.

Я создал собственный таймер с Java и Objective C. Он работает для меня и скрывает сообщение. Я не уверен, действительно ли это улучшает производительность. Как упоминалось выше: это все еще плохо для батареи и т. Д., Потому что в фоновом режиме работает долгий таймер.

Один вопрос, который следует задать, - действительно ли вам нужна функция опроса. Я думал, что да, но затем из-за этой проблемы понял, что мне нужно выполнять только _некоторый_ получастый период времени. Итак, теперь я запускаю его в фоновом режиме и полностью избегаю этой проблемы. YMMV.

такая же проблема при использовании Pusher ...

Я протестирую свое приложение, чтобы увидеть, как влияет на производительность установка таймера каждые 60 секунд.
Однако я предполагаю, что у некоторых из вас есть в этом опыт. Не могли бы вы поделиться этим опытом? Насколько сильно влияние?

все еще такая же проблема с последней версией.
любое решение?

Я тоже столкнулся с этой проблемой.
Приложение работало нормально, только когда я начал использовать firebase, появилось предупреждение.
Любое решение?

Я хочу понять смысл этого сообщения, поскольку мы начали его получать после недавней функции, которую мы добавили в наш продукт. Проблема только в том, что таймер продолжает работать, пока приложение работает в фоновом режиме? Будет ли подходящим решением подписаться на события состояния приложения и остановить таймер, если приложение работает в фоновом режиме? Или долгоиграющий таймер с приложением на _foreground_ тоже проблематичен?

Я хочу понять смысл этого сообщения, поскольку мы начали его получать после недавней функции, которую мы добавили в наш продукт. Проблема только в том, что таймер продолжает работать, пока приложение работает в фоновом режиме? Будет ли подходящим решением подписаться на события состояния приложения и остановить таймер, если приложение работает в фоновом режиме? Или долгоиграющий таймер с приложением на _foreground_ тоже проблематичен?

Хотел бы это тоже знать.

Кроме того, что происходит с setInterval? Я не получаю предупреждений от этого, но есть ли у него такая же проблема?

Я хочу понять смысл этого сообщения, поскольку мы начали его получать после недавней функции, которую мы добавили в наш продукт. Проблема только в том, что таймер продолжает работать, пока приложение работает в фоновом режиме? Будет ли подходящим решением подписаться на события состояния приложения и остановить таймер, если приложение работает в фоновом режиме? Или долгоиграющий таймер с приложением на _foreground_ тоже проблематичен?

Желтое сообщение говорит: «... и таймеры могут быть вызваны, только когда приложение находится на переднем плане».
Модуль таймера не спит, но таймеры не могут работать, когда приложение находится в фоновом режиме? Итак, проблема в том, что модуль таймера остается активным, когда приложение работает в фоновом режиме? Интересно, насколько это повлияет на производительность / батарею ...

@BerndWessels https://www.npmjs.com/package/react-native-firebase Вы это видели ? Говорит, что позволяет firebase работать в собственном потоке. Не уверен, насколько это правда, но, возможно, стоит взглянуть. Возможно, вы даже используете это, я не уверен.

Как вы думаете, если я перейду на эту библиотеку, мне придется изменить существующий код? Я имею в виду, это было бы не очень хорошо ...

та же проблема с Pusher на последней версии RN0.59, и пользовательский интерфейс может зависнуть на несколько секунд ...

Кажется, я сталкиваюсь с этой проблемой только тогда, когда звоню в базу данных реального времени firebase.

await firebase.database().ref('users/' + id).set(data);

РН 0,57,1

Я не подтвердил 0,59.

@swushi У меня такая же проблема с RN 0.59

Я получаю следующее предупреждение при использовании библиотеки firebase

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)

Как избавиться от этого предупреждения ...

Кто-нибудь знает, как избавиться от этого предупреждения, не скрывая его ??
Я использую библиотеку firebase не react-native-firebase, но, похоже, у меня та же проблема, и я не знаю, как она повлияет на меня, когда попадет в производство.

Я очень волнуюсь, поэтому, если кто-то может помочь, пожалуйста ...

Я использую следующий код, чтобы обойти эту проблему (на данный момент):

см. https://github.com/firebase/firebase-js-sdk/issues/97#issuecomment -427512040

fixtimerbug.js

/////////////////////////////////////////////////////////////////////////////
////// temporary fix to bug about 'Setting a timer' /////////////////////////
////// See: https://github.com/pusher/pusher-js/issues/248 //////////////////
////// See: https://github.com/facebook/react-native/issues/12981 ///////////
////// See: https://github.com/firebase/firebase-js-sdk/issues/97 ///////////
/////////////////////////////////////////////////////////////////////////////
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') {
  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);
  };
}
/////////////////////////////////////////////////////////////////////////////

@cpmech
Вы реализуете это в независимом файле .js или внутри скрипта, который делает исключение таймера.

Привет, да, приведенный выше код находится в файле с именем fixtimerbug.js. Затем я загружаю его в свой App.js следующим образом:

import './src/fixtimerbug'; // <<<<<<<<<<<<<<<<<<

import React from 'react';
import { Platform, View, StatusBar } from 'react-native';
import AppNavigator from './src/navigation/AppNavigator';
import Store from './src/model/Store';

const store = new Store();

const App = () => (
  <View style={{ flex: 1, backgroundColor: '#fff' }}>
    {Platform.OS === 'ios' && <StatusBar barStyle="default" />}
    <AppNavigator screenProps={{ store }} />
  </View>
);

export default App;

Вроде нормально работает, что именно делает?

Большое спасибо @cpmech

Привет, код (отсюда: https://github.com/firebase/firebase-js-sdk/issues/97#issuecomment-427512040) просто обертывает функцию setTimeout (global), чтобы предотвратить ее используется с длительным периодом.

В нашей модифицированной функции global.setTimeout , если время продолжительности больше порогового значения MAX_TIMER_DURATION_MS , мы сохраняем id на локальной карте ( timerFix ), а затем вызовите runTask который разбивает время продолжительности на меньшие значения. runTask устанавливает тайм-аут (используя исходный _setTimeout ) с меньшими фрагментами, которые будут выполняться непрерывно, пока waitingTime станет слишком маленьким. Когда waitingTime достаточно мало, мы вызываем runAfterInteractions React Native для плавного выполнения, и в то же время мы удаляем запись id с нашей локальной карты, потому что мы выиграли в этом случае больше не звонить _setTimeout . Обратите внимание, что afterTime передается в _setTimeout чтобы предотвратить его вызов с длительным периодом.

В противном случае в нашей модифицированной функции global.setTimeout , если время длительности меньше порогового значения MAX_TIMER_DURATION_MS , мы напрямую вызываем глобальный setTimeout (сохраненный в _setTimeout ).

Глобальный clearTimeout также упаковывается для выполнения процесса очистки путем удаления id с локальной карты.

Надеюсь, поможет!

Столкнувшись с той же проблемой ... Похоже, нам нужно пока скрыть предупреждение. Вот самый короткий способ сделать это:
componentDidMount() { console.disableYellowBox = true; ... }

Привет, код (отсюда: firebase / firebase-js-sdk # 97 (комментарий) ) просто обертывает функцию setTimeout (global), чтобы предотвратить ее использование в течение длительного периода.

В нашей модифицированной функции global.setTimeout , если время продолжительности больше порогового значения MAX_TIMER_DURATION_MS , мы сохраняем id на локальной карте ( timerFix ), а затем вызовите runTask который разбивает время продолжительности на меньшие значения. runTask устанавливает тайм-аут (используя исходный _setTimeout ) с меньшими фрагментами, которые будут выполняться непрерывно, пока waitingTime станет слишком маленьким. Когда waitingTime достаточно мало, мы вызываем runAfterInteractions React Native для плавного выполнения, и в то же время мы удаляем запись id с нашей локальной карты, потому что мы выиграли в этом случае больше не звонить _setTimeout . Обратите внимание, что afterTime передается в _setTimeout чтобы предотвратить его вызов с длительным периодом.

В противном случае в нашей модифицированной функции global.setTimeout , если время длительности меньше порогового значения MAX_TIMER_DURATION_MS , мы напрямую вызываем глобальный setTimeout (сохраненный в _setTimeout ).

Глобальный clearTimeout также упаковывается для выполнения процесса очистки путем удаления id с локальной карты.

Надеюсь, поможет!

Спасибо огромное! Работал как шарм.

Привет, код (отсюда: firebase / firebase-js-sdk # 97 (комментарий) ) просто обертывает функцию setTimeout (global), чтобы предотвратить ее использование в течение длительного периода.

В нашей модифицированной функции global.setTimeout , если время продолжительности больше порогового значения MAX_TIMER_DURATION_MS , мы сохраняем id на локальной карте ( timerFix ), а затем вызовите runTask который разбивает время продолжительности на меньшие значения. runTask устанавливает тайм-аут (используя исходный _setTimeout ) с меньшими фрагментами, которые будут выполняться непрерывно, пока waitingTime станет слишком маленьким. Когда waitingTime достаточно мало, мы вызываем runAfterInteractions React Native для плавного выполнения, и в то же время мы удаляем запись id с нашей локальной карты, потому что мы выиграли в этом случае больше не звонить _setTimeout . Обратите внимание, что afterTime передается в _setTimeout чтобы предотвратить его вызов с длительным периодом.

В противном случае в нашей модифицированной функции global.setTimeout , если время длительности меньше порогового значения MAX_TIMER_DURATION_MS , мы напрямую вызываем глобальный setTimeout (сохраненный в _setTimeout ).

Глобальный clearTimeout также упаковывается для выполнения процесса очистки путем удаления id с локальной карты.

Надеюсь, поможет!

Действительно ли это решает проблему или просто удаляет предупреждение?

Привет, код (отсюда: firebase / firebase-js-sdk # 97 (комментарий) ) просто обертывает функцию setTimeout (global), чтобы предотвратить ее использование в течение длительного периода.

В нашей модифицированной функции global.setTimeout , если время продолжительности больше порогового значения MAX_TIMER_DURATION_MS , мы сохраняем id на локальной карте ( timerFix ), а затем вызовите runTask который разбивает время продолжительности на меньшие значения. runTask устанавливает тайм-аут (используя исходный _setTimeout ) с меньшими фрагментами, которые будут выполняться непрерывно, пока waitingTime станет слишком маленьким. Когда waitingTime достаточно мало, мы вызываем runAfterInteractions React Native для плавного выполнения, и в то же время мы удаляем запись id с нашей локальной карты, потому что мы выиграли в этом случае больше не звонить _setTimeout . Обратите внимание, что afterTime передается в _setTimeout чтобы предотвратить его вызов с длительным периодом.

В противном случае в нашей модифицированной функции global.setTimeout , если время длительности меньше порогового значения MAX_TIMER_DURATION_MS , мы напрямую вызываем глобальный setTimeout (сохраненный в _setTimeout ).

Глобальный clearTimeout также упаковывается для выполнения процесса очистки путем удаления id с локальной карты.

Надеюсь, поможет!

Большое спасибо! Это не повлияет на общую производительность приложения, верно?

Привет, код (отсюда: firebase / firebase-js-sdk # 97 (комментарий) ) просто обертывает функцию setTimeout (global), чтобы предотвратить ее использование в течение длительного периода.
В нашей модифицированной функции global.setTimeout , если время продолжительности больше порогового значения MAX_TIMER_DURATION_MS , мы сохраняем id на локальной карте ( timerFix ), а затем вызовите runTask который разбивает время продолжительности на меньшие значения. runTask устанавливает тайм-аут (используя исходный _setTimeout ) с меньшими фрагментами, которые будут выполняться непрерывно, пока waitingTime станет слишком маленьким. Когда waitingTime достаточно мало, мы вызываем runAfterInteractions React Native для плавного выполнения, и в то же время мы удаляем запись id с нашей локальной карты, потому что мы выиграли в этом случае больше не звонить _setTimeout . Обратите внимание, что afterTime передается в _setTimeout чтобы предотвратить его вызов с длительным периодом.
В противном случае в нашей модифицированной функции global.setTimeout , если время длительности меньше порогового значения MAX_TIMER_DURATION_MS , мы напрямую вызываем глобальный setTimeout (сохраненный в _setTimeout ).
Глобальный clearTimeout также упаковывается для выполнения процесса очистки путем удаления id с локальной карты.
Надеюсь, поможет!

Действительно ли это решает проблему или просто удаляет предупреждение?

Нет, это не решает проблему. Это просто хорошая работа.

Привет, код (отсюда: firebase / firebase-js-sdk # 97 (комментарий) ) просто обертывает функцию setTimeout (global), чтобы предотвратить ее использование в течение длительного периода.
В нашей модифицированной функции global.setTimeout , если время продолжительности больше порогового значения MAX_TIMER_DURATION_MS , мы сохраняем id на локальной карте ( timerFix ), а затем вызовите runTask который разбивает время продолжительности на меньшие значения. runTask устанавливает тайм-аут (используя исходный _setTimeout ) с меньшими фрагментами, которые будут выполняться непрерывно, пока waitingTime станет слишком маленьким. Когда waitingTime достаточно мало, мы вызываем runAfterInteractions React Native для плавного выполнения, и в то же время мы удаляем запись id с нашей локальной карты, потому что мы выиграли в этом случае больше не звонить _setTimeout . Обратите внимание, что afterTime передается в _setTimeout чтобы предотвратить его вызов с длительным периодом.
В противном случае в нашей модифицированной функции global.setTimeout , если время длительности меньше порогового значения MAX_TIMER_DURATION_MS , мы напрямую вызываем глобальный setTimeout (сохраненный в _setTimeout ).
Глобальный clearTimeout также упаковывается для выполнения процесса очистки путем удаления id с локальной карты.
Надеюсь, поможет!

Большое спасибо! Это не повлияет на общую производительность приложения, верно?

Нет, на производительность это никак не влияет.

Небольшая заметка о

Если это беспокоит, просто добавьте console.ignoredYellowBox = ['Установка таймера'];

и

Столкнувшись с той же проблемой ... Похоже, нам нужно пока скрыть предупреждение. Вот самый короткий способ сделать это:
componentDidMount () {console.disableYellowBox = true; ...}

Это не подходящее решение. Ошибки все равно возникают, вы просто не получаете уведомление.

Результат? Разбор ошибок все еще должен произойти.

Например, в случае использования слушателей Firebase вы будете скрывать большое количество ошибок, но ваша среда разработки по-прежнему будет их обрабатывать.

Показательный пример: мой проект на основе expo продолжал сбой, потому что он пытался сопоставить исходную карту каждой ошибки таймера.

Я закрываю это, потому что не думаю, что React Native добавит поддержку AlarmManager в ядро. Это можно сделать с помощью сторонних модулей или собственного собственного кода.

Решение @cpmech еще работает? Я пробовал это на RN60.4, но пока не получил предупреждение о долгом таймере.

Привет, думаю, я нашел решение:
Сначала вам нужно найти в своем проекте следующий файл: libraries / Core / Timers / JSTimer; js
Откройте его, и вам просто нужно изменить эту константу MAX_TIMER_DURATION_MS, чтобы увеличить продолжительность, превышающую вашу продолжительность, написанную в конце предупреждения!

увеличить таймер, но насколько?

@dulmandakh есть ли какие-либо проекты с открытым исходным кодом, которые решают эту проблему, о которых вы знаете?

@dulmandakh есть ли какие-либо проекты с открытым исходным кодом, которые решают эту проблему, о которых вы знаете?

Может быть, @dulmandakh

Вы можете перенести таймер на фиксированное время, пока он не истечет:


const setLogoutTimer = expirationTime => {

  return dispatch => {
    timer = setTimeout(() => {
        if (expirationTime>60000)
        {
            console.log(`set new exp:${expirationTime-60000}`);
            dispatch(setLogoutTimer(expirationTime-60000));
        }
        else
        {
            console.log('logout');
            dispatch(logout());
        }
    }, 60000); 
  };
};

Прошло 2 года, и Firebase исправит эту проблему должным образом. :(

Хорошо, после нескольких часов долгого расследования, все, что я хочу знать, это то, вызвал ли я проблему каким-то образом.
Не знаю, когда это появилось.
он появляется, как только я звоню в пожарный магазин?
Я не использую таймеры в своем приложении

@luismasg Я не использую setTimeout в своем коде, так как это плохая практика, но я знаю источник ошибки, и я не могу ее остановить, и, похоже, это связано с установлением удаленного соединения с моей базой данных, очевидно, библиотека, которую я использую, устанавливает Таймаут, чтобы поддерживать TTL в рабочем состоянии, проверьте свою библиотеку зависимостей и посмотрите, можете ли вы определить причину проблемы.

Честно говоря, я не думаю, что использование таймеров / интервалов JS в любом случае является хорошей идеей для длительных таймеров, предупреждение есть не просто так.

Вместо этого используйте события жизненного цикла, чтобы добавлять / удалять короткие таймеры. Если вам нужно фактическое выполнение в фоновом режиме, используйте собственный код со службами переднего плана (Android) и фоновыми задачами (iOS).

Честно говоря, я не думаю, что использование таймеров / интервалов JS в любом случае является хорошей идеей для длительных таймеров, предупреждение есть не просто так.

Как уже упоминалось выше, многие люди борются с библиотеками, которые используют более длинные таймеры. «Просто не используйте firebase» - не решение.

Очевидно, что это часто встречающаяся проблема, решение которой улучшило бы опыт разработчика react-native что звучит так, как будто это конечная цель ...

Я бы не сказал, что «не используйте firebase» - это ответ, скорее, «исправьте firebase, чтобы не использовать длинные таймеры и использовать соответствующие стандартные строительные блоки для тех задач, для которых они используют длительные таймеры».

Но вы правы, было бы идеально, чтобы RN каким-то образом поддерживала долгие таймеры, но, учитывая все имеющиеся предостережения (например, более высокое потребление батареи, ненужное время выполнения в фоновом режиме и т. Д.), Это просто заставит разработчиков выстрелить в себя. Во всяком случае, это должен быть отдельный примитив таймера / интервала.

Во всяком случае, это должен быть отдельный примитив таймера / интервала.

Насколько я понимаю, о чем идет речь - это отсутствие такого примитива 😄

используйте таймер внутри таймера, вот и все!

@dulmandakh почему этот вопрос закрыт? Проблема сохраняется, и обсуждение продолжается?

Я добавил это в App.js, и это исправило (временно, пока не будет официального исправления)

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.startWith("_lt_")) {
      _clearTimeout(timerFix[id]);
      delete timerFix[id];
      return;
    }
    _clearTimeout(id);
  };
}

Это обходной путь, а не исправление.

Я добавил это в App.js, и это исправило (временно, пока не будет официального исправления)

...
    if (typeof id === "string" && id.startWith("_lt_")) {
...

Если вы собираетесь использовать этот код, 'startWith' должно быть 'startWith'.

Я испытываю это с AWS Amplify Datastore. Вместо правильного исправления я отключаю предупреждение с помощью

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

Мне не ясно, является ли основная проблема чем-то, что RN нужно исправить, Amplify нужно исправить, или это то, что мне нужно исправить. Очевидно, я не хочу проблем с производительностью.

Если это беспокоит, просто добавьте console.ignoredYellowBox = ['Setting a timer'];

Куда мне добавить это, я пробовал в файле экрана и файле действий, но все еще не работает

Просто поместите его где-нибудь в файл App.js. Я поместил это, например, в свой конструктор.
Не знаю, лучшее ли это место, поэтому, если кто-то знает что-нибудь получше, я бы хотел это услышать!

Я думаю, что тот, кто использует Firebase, может решить эту проблему, настроив постоянство приложения после (signIn / signUp)

* после создания нового пользователя он автоматически войдет в систему

https://firebase.google.com/docs/auth/web/auth-state-persistence

Итак ... после аутентификации пользователя создается временная переменная.

по умолчанию для firebase - local . "firebase.auth.Auth.Persistence.LOCAL"

вы можете изменить, используя:
firebase.auth.Auth.Persistence.SESSION
firebase.auth.Auth.Persistence.NONE

или используя localStorage ...

Пока они не решат это окончательно ...

import {YellowBox} из "react-native";
import _ from "lodash";
YellowBox.ignoreWarnings (["Установка таймера"]);
const _console = _.clone (консоль);
console.warn = (сообщение) => {
if (message.indexOf ("Установка таймера") <= -1) {
_console.warn (сообщение);
}
};

После решения нежелательный код удаляется и вуаля!

Это можно решить с помощью RxJS.

В основном разбивает ваш таймер 5200 на 5 * 1000 + 200 таймеры.

import { of, range } from 'rxjs';
import {
  concatMap,
  delay,
  filter,
  mapTo,
  switchMap,
  tap,
} from 'rxjs/operators';

// ~ setTimeout(..., 5200);

const source = of(5200).pipe(
  switchMap(duration => {
    const times = Math.floor(duration / 1000); // = 5
    const remainder = duration % 1000; // = 200

    return range(1, times).pipe(
      concatMap(i => of(i).pipe(delay(1000))),
      tap(console.log),
      filter(i => i === times),
      delay(remainder),
      tap(console.log),
      mapTo('Done !'),
    );
  }),
);

source.subscribe(console.log);

1 // After 1s
2 // After 2s
3 // After 3s
4 // After 4s
5 // After 5s
5 // After 5s + 200 ms
'Done !'

Я думаю, что тот, кто использует Firebase, может решить эту проблему, настроив постоянство приложения после (signIn / signUp)

* после создания нового пользователя он автоматически войдет в систему

https://firebase.google.com/docs/auth/web/auth-state-persistence

Итак ... после аутентификации пользователя создается временная переменная.

по умолчанию для firebase - local . "firebase.auth.Auth.Persistence.LOCAL"

вы можете изменить, используя:
firebase.auth.Auth.Persistence.SESSION
firebase.auth.Auth.Persistence.NONE

или используя localStorage ...

Большой! А как насчет Firestore?

Я думаю, что тот, кто использует Firebase, может решить эту проблему, настроив постоянство приложения после (signIn / signUp)
* после создания нового пользователя он автоматически войдет в систему
https://firebase.google.com/docs/auth/web/auth-state-persistence
Итак ... после аутентификации пользователя создается временная переменная.
по умолчанию для firebase - local . "firebase.auth.Auth.Persistence.LOCAL"
вы можете изменить, используя:
firebase.auth.Auth.Persistence.SESSION
firebase.auth.Auth.Persistence.NONE
или используя localStorage ...

Большой! А как насчет Firestore?

если вы используете старый SDK firebase, перейдите на SDK администратора firestore.

большинство вопросов будут решены

https://firebase.google.com/docs/reference/admin

До сих пор никто не может решить эту проблему. # позор вам, разработчики; p

До сих пор никто не может решить эту проблему. # позор вам, разработчики; p

Никогда не позорьте участников открытого исходного кода. Жаль, что это не было исправлено, но исходный код открыт, если вы знаете, как решить эту проблему, я уверен, что они оценят запрос на перенос.

Тем не менее, почему этот вопрос закрыт .

Потому что это должно быть исправлено в проблемных библиотеках. И библиотеки-нарушители не видят проблем в том, как это было реализовано.

Так что никто не станет его исправлять, потому что обе стороны не думают, что он сломан.

Их можно немного пристыдить за это 😄

Ребята, я думаю, что это не «решено» по той простой причине, что использовать долгие таймеры - крайне плохая идея.

Если вы хотите запускать таймеры в фоновом режиме / событиях в будущем, вам понадобится собственная библиотека для этого. Это также особенно сложно на обеих платформах из-за ограничений фонового выполнения.

Основываясь на комментарии @eightyfive , мы отказались от замены функций rxjs6 delay , timeout & interval .

По-прежнему остается вопрос, может ли кто-нибудь объяснить, остается ли «Модуль таймера» заблокированным при использовании меньших интервалов? Обычно просто останавливает таймер, когда приложение не на переднем плане. Или это просто скрывает проблему?

import { switchMap, concatMap, delay as nativeDelay, mapTo, filter, switchMapTo, repeat } from 'rxjs/operators'
import { range, of, race, throwError, TimeoutError } from 'rxjs'

const TIMER_INTERVAL = 1000
const reactNativeTimer = (duration) => {
  const times = Math.floor(duration / TIMER_INTERVAL)
  const remainder = duration % TIMER_INTERVAL
  if (times < 1) {
    return of(true).pipe(nativeDelay(remainder))
  }
  return range(1, times).pipe(
    concatMap(i => of(i).pipe(nativeDelay(TIMER_INTERVAL))),
    filter(i => i === times),
    nativeDelay(remainder)
  )
}

/**
 * React Native compatible version of delay pipe
 * <strong i="11">@param</strong> {number} duration in ms
 */
export const delay = (duration) => {
  return (source) => {
    return source.pipe(
      switchMap(next =>
        reactNativeTimer(duration).pipe(mapTo(next))
      )
    )
  }
}

/**
 * React Native compatible version of timeout pipe
 * <strong i="12">@param</strong> {number} duration in ms
 */
export const timeout = (duration) => {
  return (source) => {
    const timeoutTimer = reactNativeTimer(duration).pipe(
      switchMapTo(throwError(new TimeoutError()))
    )
    return race(source, timeoutTimer)
  }
}

/**
 * React Native compatible version of interval
 * <strong i="13">@param</strong> {number} duration in ms
 */
export const interval = (duration) => {
  return reactNativeTimer(duration).pipe(
    repeat()
  )
}

Самое смешное, что все в этой ветке обсуждают обходной путь, чтобы игнорировать это предупреждение.
Когда я был перенаправлен на эту «проблему» из-за предупреждения, я надеялся найти соответствующую документацию, объясняющую «как?» чтобы справиться с этим, и еще немного рассуждений о «почему?».

интерфейс # миллениалы

Этот #millenial хотел бы отметить, что:

  • Эта ошибка не требует документации, она говорит сама за себя: вы установили длинный таймер.
  • В этой ветке полно людей, отключающих предупреждения для библиотек, которыми они не владеют (например, firebase).
  • Как показывает (продуктивное) обсуждение в этой ветке, это более сложная проблема, которую нужно исправить в react-native

Тем не менее, я еще раз укажу, что эту проблему не следует закрывать, она помечена known-issue и Help Wanted .

Millenial ответы на millenial :)

Эта ошибка не требует документации, она говорит сама за себя: вы установили длинный таймер.

  • Это не ошибка, а предупреждение (не спрашивайте меня о разнице, иначе придется начинать глубокий философский разговор :))
  • Он уже претендует на то, чтобы быть задокументированным из-за предоставленной ссылки на этот билет, где мне нужно прочитать массу комментариев вместо резюме (что-то вроде известной проблемы, как вы уже предложили):
    image
  • Я бы не сказал, что это говорит само за себя. Недостаточно контекста. Буквально в описании есть два предложения.

Тем не менее, я еще раз укажу, что эту проблему не следует закрывать, она помечена как известная проблема и требуется помощь.

Полностью согласен. Это сэкономит время многим людям, переходящим по URL-адресу в предупреждении.

Для пользователей firebase / firestore: я просто вернулся к использованию конечных точек REST непосредственно для вызовов firestore. Поскольку мне нужны были только auth и firestore, это довольно легко решило мои проблемы. Фрагмент здесь:

https://stackoverflow.com/a/62446792

Я сделал это внутри App () следующим образом:

импортировать {YellowBox} из 'react-native';
экспортировать функцию по умолчанию App () {
YellowBox.ignoreWarnings (['Установка таймера']);
...
...
..
}

Remeber

Что я сделал, и это работает со мной, но я до сих пор не знаю, хорошая это практика или нет

Переход к файлу

node_modulesreact-native \ Libraries \ Core \ TimersJSTimers.js

есть функция const MAX_TIMER_DURATION_MS = 60 * 1000 и я увеличил время до 60 * 100000, и она перестала появляться

Привет всем,
Этой проблеме около 3 лет, и у нас все еще есть это предупреждение;)
как сказал @RWOverdijk, игнорирование предупреждения не является решением.
Есть ли решение, которое я пропустил?

Спасибо <3

Привет всем, мы решаем заблокировать этот выпуск. Я знаю, что эта проблема расстраивает многих из вас, и я хочу найти время, чтобы помочь понять, почему мы принимаем это решение.

Как таймеры работают на Android в React Native

React Native имеет собственную реализацию таймеров JS, например setTimeout . На Android это работает так, что таймеры JS отслеживаются на нативной стороне, и нативная сторона решает, когда запускать эти таймеры. Это позволяет React Native лучше понимать, когда срабатывают таймеры, и в частности, как они связаны с жизненным циклом приложения и рендерингом.

Что будет, если я установлю таймер с большим интервалом?

Вот мое понимание после прочтения кода и его небольшого тестирования:

  1. Если вы установили длительный таймер, и приложение остается открытым в течение всего времени, когда таймер активен, таймер должен работать.
  2. Если вы установили длительный таймер и телефон отключился до того, как таймер закончился, таймер не будет активирован, пока вы не откроете приложение в следующий раз.
  3. Есть исключение для задач JS без головы, которые могут поддерживать работу таймеров, даже если приложение находится в фоновом режиме.

Почему бы нам не вызывать таймеры с большими интервалами?

Я думаю, что это в первую очередь проблема правильности, а не производительности. Проблема в том, что вы не можете полагаться на долгие таймеры, если пользователь создает ваше приложение.

Если вы не возражаете, чтобы ваш таймер был активирован позже, когда приложение снова выйдет на передний план, то я думаю, что игнорирование предупреждения YellowBox - хорошая идея.

С другой стороны, если ваш таймер ожидает вызова на время существования сеанса и не должен запускаться снова на переднем плане, вам нужно будет что-то сделать, чтобы убедиться, что таймер игнорируется на переднем плане.

Как использовать сторонние библиотеки, такие как Socket.io и Firebase, которые устанавливают длительные таймеры?

Я не знаю подробностей об этих сторонних библиотеках. В конечном итоге все сводится к поставленному выше вопросу. Если в этих сторонних библиотеках будут проблемы с таймерами, решаемыми на переднем плане, вам нужно будет найти способ исправить это. В некоторых приведенных выше комментариях предлагаются способы сделать это, например, для Firebase. Однако в конечном итоге вам может быть лучше полагаться на библиотеку, разработанную специально с учетом React Native.

С другой стороны, если сторонняя библиотека не имеет проблем с таймерами, разрешенными на переднем плане, вы можете игнорировать ошибку.

Почему не может setTimeout пройти через AlarmManager , как было предложено изначально?

AlarmManager разбудит приложение, если оно работает в фоновом режиме, и мы не думаем, что таймеры вроде setTimeout должны будить приложение. Большинство этих длительных таймеров настроены на такие вещи, как тайм-ауты, и они актуальны только тогда, когда приложение открыто. Пробуждение приложения в фоновом режиме стоит дорого и должно выполняться только в том случае, если разработчик явно имеет такое намерение.

В то же время, наверное, у многих есть потребность в чем-то подобном. Мы могли бы разработать для него API, который не проходит через setTimeout . Но из-за усилий по Lean Core прямо сейчас мы на самом деле пытаемся избежать увеличения поверхности API для React Native. Мы считаем, что с этой задачей лучше всего справится сторонняя библиотека, например react-native-background-timer .

Почему бы вам тогда не удалить предупреждение полностью?

Мы хотим, чтобы разработчики знали, что происходит. Если кто-то устанавливает библиотеку, которая полагается на правильность setTimeout , мы думаем, что разработчик должен знать, что мы не можем гарантировать эту правильность. Мы хотим оставить на усмотрение отдельных разработчиков решение о том, имеет ли значение это предупреждение в их конкретном случае использования.

Была ли эта страница полезной?
0 / 5 - 0 рейтинги