У меня есть пользовательский скрипт (Tampermonkey в Chrome), который запускается либо при открытии страницы пользователем, либо может открывать страницу в отдельном окне (где затем запускается соответствующий скрипт). Когда страница открывается пользователем, все работает как положено.
Однако, когда страница открывается в другом окне, эта функция иногда не обрабатывает текст должным образом.
Код:
function processTableRows() {
var regex = new RegExp(/(.*?)(\d{7})/);
var texts = document.querySelectorAll(".table__row");
var out = [];
texts.forEach(text=> {
var fixMonth = text.innerText.replace(/(\d*)月/, function(p1) {
const monthNames = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
return monthNames[(parseInt(p1) - 1)];
}).replace(regex,
"example.com/page.html?id=$2\n$1");
out.push(fixMonth);
});
return out;
}
Пример текста страницы (до скрипта):
05 6月 2019 8989898
Some text
Some more text
При пользователь открывает страницу и пользовательский скрипт, и код в консоли дают ожидаемый результат:
example.com/page.html?id=8989898
05 Jun 2019
Some text
Some more text
Однако, когда он запускается в отдельном окне, он возвращает (как скрипт TM, так и консоль):
05 Jun 2019
example.com/page.html?id=8989898
Some text
Some more text
Я не могу себе представить, почему второй replace() работает по-другому в отдельном окне. Я думал, что это может быть связано с некоторыми забавными регулярными выражениями JavaScript, например. перемещение индекса, влияющее на связанный вызов, но MDN указывает, что он возвращает только строку.
Обновлено: Дополнительная информация, полученная после комментариев, которые были ниже:
Когда страница запускается в новом (всплывающем) окне, она маленькая, а исходный текст выглядит так:
05 6月 2019
8989898
Some text
Some more text
Однако, когда окно больше (например, когда пользователь посещает его), оно выглядит так:
05 6月 2019 8989898
Some text
Some more text
Я очень хорошо осведомлен об использовании минимальных воспроизводимых примеров; для меня невозможно предоставить копию веб-сайта или намного больше, чем ранее предоставленный текст. Тем не менее, ваш предыдущий комментарий был правильным - это было связано с тем, что размеры открытого окна различались, что приводило к изменению отображаемого пробела (и, следовательно, значения innerText). textContent предоставляет стабильную ссылку, подходящую для последовательного форматирования, большое спасибо!
@BrockAdams Эти знания о textContent были именно тем, что мне было нужно, чтобы исправить некоторые другие вечные ошибки (и, несомненно, избежать бесчисленных других в будущем); Я бы с удовольствием принял это как ответ, если вы хотите что-нибудь придумать. Спасибо еще раз!



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


В общем, если один и тот же пользовательский скрипт дает разные результаты — на одной и той же странице — в зависимости от того, как открывается эта страница, причины могут быть следующими:
Сроки. Страница загружается медленнее или быстрее в зависимости от различных факторов, часто кэшируется. Таким образом, сценарий может сработать до того, как искомый контент будет представлен/закончен.
Используйте waitForKeyElements или MutationObserver для компенсации. Поищите предыдущие вопросы, где это было рассмотрено.
АЯКС. На самом деле страница не выполняет обычную загрузку HTML, а использует javascript для (пере)записи «новой» страницы.
Опять же, против таких страниц помогают waitForKeyElements или MutationObserver. И, опять же, рассмотрено в предыдущих вопросах.
«Отзывчивый» макет/поведение. На одной и той же странице может отображаться разный контент и/или по-разному в зависимости от размера окна (как правило), отслеживания состояния или некоторых переданных параметров.
В таком случае вашему сценарию может понадобиться логический код для адаптации к различным вариантам страницы.
Код, чувствительный к рендерингу. Если ваш скрипт зависит от позиционирования, стиля CSS, размеров элементов и т. д.; он может сломаться просто из-за того, что окно имеет другой размер или когда для отображения страницы требуется разное время.
В этом случае код вопроса имеет вариант причины 4. Он использует innerText и innerText меняет свои результаты в зависимости от пробелов и видимости. (innerText также медленнее, чем textContent.)
Решение используйте textContent вместо innerText.
Вот демонстрация, показывающая, как эти два свойства могут отличаться:
srcNode = $(".variableDiv")[0];
$("#TC").text (srcNode.textContent);
$("#IT").text (srcNode.innerText);.variableDiv {border: 1px solid gray; margin-bottom: 1em;}
td, th {border: 1px solid gray; padding: 0.2ex 1ex;}
table {border-collapse: collapse;}<script src = "https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Source Div:
<div class = "variableDiv">
Chuck Norris has two speeds: <br> Walk, and Kill.<br>
<span style = "display:none">Hidden Text</span>
</div>
<table>
<tr> <th>textContent</th> </tr>
<tr> <td><pre id = "TC"> </pre></td> </tr>
<tr> <th>innerText</th> </tr>
<tr> <td><pre id = "IT"> </pre></td> </tr>
</table>IIRC, разные браузеры также могут различаться результатами innerText при скрытом переполнении и/или перекрывающих элементах, но я этого не проверял.
Абсолютно гениально, и еще раз спасибо! Небольшой вопрос по использованию waitForKeyElements с проблемами синхронизации/AJAX — эта страница загружает информацию с помощью AJAX, и мой скрипт ранее использовал waitForKeyElements для поддержки этого. С тех пор я изменил его так, что у меня есть функция, которая проверяет, существует ли элемент, и снова вызывает себя через setTimeout(), если это не так. Есть ли проблемы с этим или какие-то другие преимущества, предоставляемые waitForKeyElements, о которых я не знаю?
@Altigraph, лучше использовать setInterval для таких вещей. Повторяющиеся/сцепленные setTimeout в некоторых случаях могут стать хитом памяти/производительности. ... Преимущества waitForKeyElements: (1) простота использования, (2) проще иметь несколько или цепочку ожиданий без конфликтов, (3) код вашего скрипта более «самодокументируемый», (4) его легче изменить/расширить. ... Но используйте то, что работает для вас (и тех, кто будет работать с кодом через пару лет (даже если это вы сами в будущем)).
Целевая страница не является общедоступной; чтобы было ясно, когда я имею в виду невозможность воспроизвести его в консоли, то есть включить в консоль окно, открытое сценарием, поэтому в окончательном рендеринге не должно быть никакой разницы. Возможно, это проблема времени, хотя я ожидаю, что в этом случае это также произойдет при открытии пользователем. Я посмотрю на
textContentи посмотрю, даст ли это другие/лучшие результаты.