Обратный вызов возвращается неопределенным с 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, когда они учатся использовать асинхронные вызовы.