Chrome.runtime.onMessage ответ с асинхронным ожиданием

Я хочу использовать async ждут в прослушивателе onMessage:

chrome.runtime.onMessage.addListener(async (request, sender, sendResponse) =>{
    var key = await getKey();
    sendResponse(key);
});

Однако я получаю undefined, когда я отправляю сообщение.

Из документации для chrome.runtime.onMessage.addListener:

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

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

chrome.runtime.onMessage.addListener(async (request, sender, sendResponse) =>{
    getKey(key => {
        sendResponse(key);
    });
    return true;
});

Однако я бы хотел использовать синтаксис ожидания. Но он не работает и все еще возвращает undefined:

chrome.runtime.onMessage.addListener(async (request, sender, sendResponse) =>{
    var key = await getKey();
    sendResponse(key);
    return true;
});

Ответ 1

Я обойти, извлекая в асинхронную функцию.

chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
  doSomethingWith(request).then(sendResponse);
  return true; // return true to indicate you wish to send a response asynchronously
});

async function doSomethingWith(request) {
  var key = await getKey();
  // await .....
  return key;
}

Возвращаемое значение async функции неявно Promise.resolve в Promise.resolve. Смотрите асинхронный док.

Смотрите на сообщение.

Ответ 2

Не уверен, что среда выполнения расширений Chrome поддерживает синтаксис async/await, но вы можете использовать транспортер (например, Babel) для его преобразования, например, в ES5. Затем вы можете определить функцию-оболочку следующим образом:

function asChromeListener(listener) {
  return (message, sender, sendResponse) => {
    const returnValue = listener(message, sender);

    if (isPromise(returnValue)) {
      returnValue.then(sendResponse);
      return true;
    }
    else {
      if (typeof returnValue !== 'undefined') {
        sendResponse(returnValue);
      }
      return false;
    }
  };
}

function isPromise(value) {
  return typeof value === 'object' && value !== null && 'then' in value && 'catch' in value;
}

Что вы можете использовать как:

chrome.runtime.onMessage.addListener(asChromeListener(async (message, sender) => {
  return await doMyAsyncWork(message);
});

Так как мы используем TypeScript, здесь также фрагмент, который мы фактически используем (с общими типами).

export function asChromeListener<M, S, R extends Function>(listener: (message: M, sender: S) => any) {
  return (message: M, sender: S, sendResponse: R) => {
    const returnValue = listener(message, sender);

    if (isPromise(returnValue)) {
      returnValue.then(sendResponse);
      return true;
    }
    else {
      if (typeof returnValue !== 'undefined') {
        sendResponse(returnValue);
      }
      return false;
    }
  };
}

function isPromise(value: any) {
  return typeof value === 'object' && value !== null && 'then' in value && 'catch' in value;
}

Ответ 3

Честно говоря, похоже, что расширения Google Chrome не поддерживают ключевое слово await. Я успешно использовал асинхронный chrome.runtime.onMessage.addListener раньше, и каждый раз, когда я пытаюсь использовать await, я вижу эту синтаксическую ошибку в средствах отладки Chrome, в строке, которую я использую await:

ждать не поддерживается

Вот как я тестировал:

Я создал очень простой слушатель:

chrome.runtime.onMessage.addListener(function(data, MessageSender, sendResponse) {
    sendResponse(awaitTester);
    var async = true;

    // returns true if asyncronous is needed
    if (async) return true;
});

Моя функция awaitTester выглядит следующим образом:

function awaitTester() {
    var prom = new Promise(function(resolve, reject) {
        setTimeout(function() {
            resolve('test');
        }, 4000);
    });

    var awaited = await prom;
    return awaited;
}

наконец, мой отправитель сообщения - это то, что вы ожидаете:

chrome.runtime.sendMessage({}, function(message) {
    debugger;
    console.log(message);
});

И в отладчике/консоли я всегда получаю undefined.