Обратный вызов возвращается неопределенным с chrome.storage.sync.get

Я строю расширение Chrome и написал этот код.

var Options = function(){};

Options.prototype = {

    getMode: function(){
               return chrome.storage.sync.get("value", function(e){  
                 console.log(e); // it prints 'Object {value: "test"}'.       
                 return e;
               });
    },

    setMode: function(){
        chrome.storage.sync.set({"value": "test"}, function(e) {         
        })
    }
}

var options = new Options();
options.setMode();
console.log(options.getMode()); // it prints 'undefined'.

Я ожидал это напечатать

Object {value: "set up"}

когда я звоню options.getMode(), но это печатает undefined,

Кто-нибудь знает, как решить эту проблему?

2 ответа

Решение

chrome.storage API является асинхронным - он не возвращает его напрямую, а передает его в качестве аргумента функции обратного вызова. Сам вызов функции всегда возвращает undefined,

Это часто используется, чтобы позволить другим методам запускаться, не дожидаясь, пока что-то ответит или завершит - пример этого setTimeout (единственное отличие состоит в том, что он возвращает значение таймера, а не undefined).

Например, возьмите это:

setTimeout(function () { alert(1); }, 10000);
alert(0);

Так как setTimeout является асинхронным, он не остановит весь код до тех пор, пока вся функция не завершится, а вернется вначале, вызывая только функцию, когда она будет завершена позднее - вот почему 0 поднимается до 1.


По этой причине вы не можете просто сделать что-то вроде:

// "foo" will always be undefined
var foo = asyncBar(function (e) { return e; }); 

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

function getValue(callback) {
  chrome.storage.sync.get("value", callback);
}

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

console.log(getValue()); // typical synchronous method of doing something

Это, вероятно, будет лучшей идеей:

// how it would be done in asynchronous code
getValue(function (value) {
  console.log(value);
}); 

API хранилища Chrome является асинхронным и использует callbackВот почему вы получаете это поведение.

Вы можете использовать Promise API для преодоления этой асинхронной проблемы, которая проще и чище. Вот пример:

async function getLocalStorageValue(key) {
    return new Promise((resolve, reject) => {
        try {
            chrome.storage.sync.get(key, function (value) {
                resolve(value);
            })
        }
        catch (ex) {
            reject(ex);
        }
    });
}

const result = await getLocalStorageValue("my-key");

chrome.storage.sync.get вызывается асинхронно, поэтому вы должны передать ему обратный вызов, чтобы он выполнялся в будущем.

При попытке напечатать возвращенное значение getModeвы печатаете возвращаемое значение любого chrome.storage.sync.get возвращается в очередь после выполнения асинхронного вызова.

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

Другие вопросы по тегам