window.pageYOffset иногда 0 вместо действительного значения - PullRequest
0 голосов
/ 05 июля 2018

У меня проблема с тем, что иногда, когда мой JavaScript на веб-странице получает значение window.pageYOffset, это необъяснимо 0, хотя я знаю, что пользователь просматривает середину документа, и его значение должно быть огромным, например 650000. Обратите внимание, что огромный процент времени я получаю разумное значение. Но иногда это ноль, а иногда это, казалось бы, случайное небольшое значение, как в диапазоне 6000, когда я ожидаю 650000.

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

Эта страница отображается в iOS WKWebView (хотя эта проблема может проявляться в аналогичном контексте в приложении для Android). Методы JavaScript в моем приложении могут быть вызваны одним из следующих способов:

  1. Когда мое приложение получает уведомление о завершении загрузки страницы (с помощью метода делегата), оно вызывает метод JavaScript, используя evaluateJavaScript из кода Objective-C.

  2. Мое приложение может вызывать evaluateJavaScript в другое время, а не только после завершения загрузки страницы.

  3. Функция JavaScript может быть вызвана в результате срабатывания таймера.

  4. Функция JavaScript может быть вызвана в результате события прокрутки.

Я действовал в предположении, что код JavaScript на странице всегда работает в одном потоке. То есть у меня нет ситуации, когда срабатывание таймера, событие прокрутки или даже вызов из кода Objective-C (с использованием evaluateJavaScript) прерывает все, что может происходить во время выполнения JavaScript. Поэтому мне не нужно беспокоиться о прерывании некоторых действий системного уровня, которые изменяют window.pageYOffset, пока я пытаюсь получить к ним доступ.

Итак, это мой первый вопрос: правильно ли я, что кто-то вне моего кода вызывает мои методы JavaScript в одном потоке, а не манипулирует DOM в другом потоке?

Мой второй вопрос связан с тем, что мой код изменяет DOM, добавляя и удаляя элементы div. Я предполагал, что эти изменения являются синхронными - если я вставлю элемент с insertAfter или insertBefore, я ожидаю, что указатели child / parent / sibling верны по возвращении, и я предполагаю, что я могу сразу получить доступ к вещам как и значения top и left для какого-либо другого элемента, и они будут обновлены для отражения вставленного / удаленного элемента. Дело в том, что мне не нужно «ждать», пока DOM «стабилизируется» после внесения изменений и перед проверкой чего-то вроде window.pageYOffset. Это правильно?

Еще одна подсказка: чтобы помочь смягчить это, мне повезло, просто протестировав window.pageYOffset на ноль в верхней части функции. Если он равен нулю, я перезваниваю по таймеру (с задержкой всего в 1 мс). Если я сделаю это достаточно долго, это в конечном итоге будет ненулевым.

Возможно, после прочтения всего этого, ни одна из деталей не имеет значения, и вы знаете ответ на основной вопрос: почему я иногда получаю недопустимое значение (обычно 0) в window.pageYOffset, когда одна и та же строка кода дает действительный значение в другое время.

1 Ответ

0 голосов
/ 10 июля 2018

Проблема оказалась в том, что, по-видимому, существует промежуток времени между тем, когда я даю WKWebView новую HTML-строку для рендеринга, и когда она сообщает мне, что загрузка страницы завершена, что существующая страница все еще активный. В течение этого времени таймеры продолжают срабатывать, но некоторые свойства document и window будут недействительными.

Из-за сложности отладки JavaScript, работающего в этой среде, я обманом заставил себя подумать «в конечном итоге pageYOffset станет действительным», когда на самом деле я увидел, что новая страница в конечном итоге закончила загружаться, и это была новая страница, которая генерировала допустимые вызовы для моих функций таймера.

В моем конкретном случае (может не работать для всех) я могу обнаружить значение window.pageYOffset в верхней части функции таймера, и если оно равно 0, перезвонить себе после небольшой задержки. Это позволяет мне обрабатывать случай, когда по какой-то причине window.pageYOffset просто еще не действителен (мой тест в конечном итоге пройдет, и моя функция таймера продолжится как обычно), и случай, когда все находится в процессе отбрасывания в пользу новой страницы (в этом случае таймер не сработает, потому что страница уходит).

...