Обещание асинхронного расширения Javascript Chrome

#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. Хорошо, спасибо, теперь я понимаю, что то, что я пытаюсь сделать, невозможно. Я думаю, мне придется изучить сторону обмена сообщениями и посмотреть, работает ли это