#javascript #google-chrome-extension #promise
#javascript #google-chrome-extension #обещание
Вопрос:
Довольно новичок в chrome extensions, поэтому в процессе создания чего-то довольно простого с помощью простого всплывающего окна.
Все работает нормально, но мне пришлось использовать chrome.tabs.executeScript, чтобы получить массив содержимого из DOM (ссылки), затем идея состоит в том, чтобы представить их во всплывающем окне. Поскольку chrome.tabs.executeScript выполняется синхронно по сравнению с остальными, работающими асинхронно, я получаю неопределенные ошибки.
Чтобы попытаться обойти это, я обернул вызов chrome.tabs.executeScript внутри promise и, используя синтаксис then(), вызвал мои последующие функции. К сожалению, массив, который я заполняю, все еще не определен, поэтому, похоже, обещание работает не так, как ожидалось.
Не судите о соглашении об именах, оно все еще WIP, и все будет приведено в порядок.
Mainfest:
{
"manifest_version": 2,
"name": "One-click Kittens",
"description": "This extension demonstrates a browser action with kittens.",
"version": "1.1",
"permissions": [
"https://secure.flickr.com/",
"activeTab"
],
"browser_action": {
"default_icon": "img/icon.png",
"default_popup": "popup.html"
}
}
popup.js
globalThis.getText = [];
var kittenGenerator = {
requestKittens: function () {
return new Promise(function(resolve, reject) {
chrome.tabs.executeScript({ code: `(${inContent})()` });
resolve();
}
);
function inContent() {
const el = document.getElementsByTagName('audio');
this.getText = el;
//DEBUG
for (var i = 0; i < this.getText.length; i ) {
console.log(this.getText[i]);
}
}
},
showTracks_: function (e) {
var kittens = this.getText;
console.log(this.getText);
for (var i = 0; i < kittens.length; i ) {
console.log(kittens[i]);
var img = document.createElement('button');
img.id = 'dl';
img.value = kittens[i].getAttribute('src');
img.innerText = 'Dl';
document.body.appendChild(img);
}
}
};
// Run our kitten generation script as soon as the document's DOM is ready.
document.addEventListener('DOMContentLoaded', function () {
kittenGenerator.requestKittens().then(kittenGenerator.showTracks_());
});
Идея состоит в том, чтобы захватить определенные аудиоэлементы из DOM, а затем я могу отобразить список кнопок во всплывающем окне.
Если кто-нибудь сможет определить, где я ошибся с обещаниями, я был бы признателен.
Ответ №1:
Проблема заключается не во внешнем интерфейсе executeScript (обещание или обратный вызов), а в том факте, что ваш inContent на самом деле ничего не возвращает, поэтому (${inContent})()
оценивает undefined
.
Так что просто верните что-нибудь значимое:
function inContent() {
return [...document.getElementsByTagName('audio')]
.map(el => [el.id, el.textContent]);
}
Возвращаемые данные должны быть совместимы с JSON (number, string, boolean, null и объекты / массивы, состоящие из этих типов). Попытка вернуть элемент DOM или обещание или карту / набор приведет к пустому {}
.
Комментарии:
1. Итак, возвращая сообщение «return document.getElementsByTagName(‘audio’);», который представляет собой массив элементов в inContent, должен сделать трюк? Если это так, то массив getText по-прежнему не определен, и по-прежнему кажется, что обещание игнорируется
2. Я думал, вы знаете, что
inContent
это выполняется только в контексте сценария содержимого, ничего больше, поэтому он не может видеть другие неинъекционные функции. Кроме того, как вы можете видеть, в моем ответе явно упоминается, что вы не можете возвращать элементы DOM.3. Я понимаю разницу между inContent, работающим как сценарий содержимого, и сценарием расширения. Даже если я беру элементы DOM, помещаю их в массив (как вы указали, разрешено), тогда все равно this.getText не определен, я предполагаю, что из-за асинхронного характера он попадает в эту часть кода до завершения других частей, отсюда и предложение Promise and .then(). Возможно ли то, что я даже пытаюсь сделать — взять элементы DOM и передать их в мой popup.js файл?
4. Очевидно, я очень плохо умею объяснять, поэтому я просто попытаюсь перефразировать ответ. Проблема не связана с async или Promise, и нет, inContent не запускается как сценарий расширения: он объявлен там, но он там не запускается, он запускается только как сценарий содержимого через executeScript. Сценарий содержимого выполняется на совершенно другой странице, на которой нет ни одного из методов, определенных в вашем сценарии расширения. Вы не можете перенести элементы DOM из введенного кода в обратный вызов executeScript.
5. Хорошо, спасибо, теперь я понимаю, что то, что я пытаюсь сделать, невозможно. Я думаю, мне придется изучить сторону обмена сообщениями и посмотреть, работает ли это