Возврат значения API хранилища Chrome без функции

Последние два дня я работаю с асинхронным хранилищем Chrome. Это работает "хорошо", если у вас есть функция. (Как ниже):

chrome.storage.sync.get({"disableautoplay": true}, function(e){
console.log(e.disableautoplay);
});

Моя проблема в том, что я не могу использовать функцию с тем, что я делаю. Я хочу просто вернуть его, как может LocalStorage. Что-то вроде:

var a = chrome.storage.sync.get({"disableautoplay": true});

или же

var a = chrome.storage.sync.get({"disableautoplay": true}, function(e){
    return e.disableautoplay;
});

Я пробовал миллион комбинаций, даже устанавливая открытую переменную и устанавливая, что:

var a;
window.onload = function(){
    chrome.storage.sync.get({"disableautoplay": true}, function(e){
    a = e.disableautoplay;
});
}

Ничего не работает Все это возвращает неопределенное значение, если только код, ссылающийся на него, не находится внутри функции get, и это бесполезно для меня. Я просто хочу иметь возможность возвращать значение в качестве переменной.

Это вообще возможно?

РЕДАКТИРОВАТЬ: Этот вопрос не является дубликатом, пожалуйста, позвольте мне объяснить, почему:

1: нет других постов, специально спрашивающих об этом (на всякий случай я потратил два дня на просмотр).

2: мой вопрос все еще не отвечен. Да, Chrome Storage является асинхронным, и да, он не возвращает значение. Это проблема. Я уточню ниже ...

Мне нужно иметь возможность получить сохраненное значение вне функции chrome.storage.sync.get. Я не могу использовать localStorage, так как он специфичен для URL, и к тем же значениям нельзя получить доступ как со страницы browser_action расширения chrome, так и из background.js. Я не могу сохранить значение с помощью одного сценария и получить доступ к нему с помощью другого. Они рассматриваются отдельно.

Поэтому мое единственное решение - использовать Chrome Storage. Должен быть какой-то способ получить значение сохраненного элемента и ссылаться на него вне функции get. Мне нужно проверить это в утверждении if.

Так же, как localStorage может сделать

if(localStorage.getItem("disableautoplay") == true);

Должен быть какой-то способ сделать что-то вроде

if(chrome.storage.sync.get("disableautoplay") == true);

Я понимаю, что это не будет так просто, но это лучший способ объяснить это.

Каждый пост, который я вижу, говорит, что нужно делать так:

chrome.storage.sync.get({"disableautoplay": true, function(i){
    console.log(i.disableautoplay);
    //But the info is worthless to me inside this function.
});
//I need it outside this function.
 Xan18 июл. 2016 г., 10:35
Дополнительное чтение:stackoverflow.com/questions/11688171/...
 ndreisg27 авг. 2019 г., 14:41
Я знаю, что этот вопрос довольно старый, но просто чтобы его заметили: в настоящее время вы будете использовать async / await для достижения именно того, что нужно оператору. Увидетьstackoverflow.com/questions/14220321/...
 Eiko19 июл. 2016 г., 06:50
Связанный вопрос отвечает, как обойти это. Почему результат будет "бесполезным" для вас? Просто организуйте свой код соответствующим образом и работайте со структурой, а не против нее. В чем твоя настоящая проблема здесь?
 adamj19 апр. 2017 г., 07:47
В конце концов, я использовал начальныйsync.get как временныйinit метод, чтобы установить внешнюю переменную с данными заголовка, прежде чем я запустил$.get, который вызвал$.ajaxSetup
 Xan19 июл. 2016 г., 10:42
* вздох * Хорошо, значит, вы (этот канонический!) обманут. Это все равно не принесет вам пользы, если вы не поймете, как бороться с асинхронностью. Это большая концептуальная тема, но ее нужно понимать, если вы хотите программировать на JavaScript.
 Keith DC08 февр. 2018 г., 01:55
Завершение этого в обещание, как показано в этой сути, сработало для меня ...gist.github.com/mvanlonden/...
 adamj19 апр. 2017 г., 07:34
Я столкнулся с аналогичной проблемой, с помощью которойchrome.storage.sync.get изнутриbeforeSend из$.ajaxSetup пытаясь сделатьsetRequestHeader просто не сработает. Если вы не делаетеsetRequestHeader снаружиsync.get, но если вы сделаете это, у вас не будет доступа к данным, которые вы хотите добавить в заголовок, так как они находятся внеsync.get.

Ответы на вопрос(3)

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

chrome.storage.sync.get такжеасинхронный метод, который объясняет, почему в следующем кодеa было быundefined если вы не обращаетесь к нему внутри функции обратного вызова.

var a;
window.onload = function(){
    chrome.storage.sync.get({"disableautoplay": true}, function(e){
        // #2
        a = e.disableautoplay; // true or false
    });
    // #1
    a; // undefined
}
 Haibara Ai18 июл. 2016 г., 13:31
@Xan, понял, я начну записку, чтобы записать вопросы, связанные с популярными расширениями.
 Haibara Ai19 июл. 2016 г., 02:04
@KyleHickey, почему бы не поместить логику «получить значение из возвращенного» внутри обратного вызова? Мое предложение по-прежнему будет «Понимание обратного вызова и его использование», так какбольшинство методов в chrome. * apis являются асинхронными
 Xan18 июл. 2016 г., 10:39
Хайбара, пожалуйста, уделите минутку, чтобы добавить в закладки цель-обманщика и дополнительный вопрос, который я связал в комментариях Это часто используемые ссылки.
 Kyle Hickey18 июл. 2016 г., 17:17
Я понимаю, что у него нет возвращаемых значений, но мне нужно каким-то образом получить возвращаемое значение ... должен быть какой-то способ получить его.

хорошо, вы получите свой индивидуальный ответ на свой вопрос. Это все еще будет 90% -ным объяснением, почему вы не можете обойти асинхронные, но потерпите меня - это поможет вам в целом. Я обещаю, что есть что-то подходящее дляchrome.storage в конце.

Прежде чем мы начнем, я повторю канонические ссылки для этого:После вызова chrome.tabs.query результаты недоступны
(Chrome конкретный, отличный ответ от RobW,наверное проще всего понять)Почему моя переменная не изменилась после того, как я изменил ее внутри функции? - асинхронная ссылка на код (Общая каноническая ссылка на то, что вы просите)Как вернуть ответ от асинхронного вызова?
(более старый, но не менее уважаемый канонический вопрос об асинхронном JS)Вы не знаете JS: асинхронность и производительность (электронная книга по асинхронности JS)Итак, давайте обсудим асинхронность JS.Раздел 1: Что это?

Первая концепция для покрытиясреда выполнения, JavaScript, в некотором роде, встроен в другую программу, которая контролирует поток выполнения - в данном случае, Chrome. ВсеСобытия это происходит (таймеры, щелчки и т. д.) из среды выполнения. Код JavaScript регистрирует обработчики для событий, которые запоминаются средой выполнения и вызываются соответствующим образом.

Во-вторых, важно понимать, что JavaScript является однопоточным. Есть одинцикл событий поддерживается средой выполнения; если есть какой-то другой код, выполняющийся, когда происходит событие, это событие помещается в очередь для обработкикогда текущий код заканчивается.

Посмотрите на этот код:

var clicks = 0;

someCode();
element.addEventListener("click", function(e) {
  console.log("Oh hey, I'm clicked!");
  clicks += 1;
});
someMoreCode();

Итак, что здесь происходит? Как этот код выполняется, когда выполнение достигает.addEventListenerпроисходит следующее:среда выполнения уведомляется о том, что когда происходит событие (element щелчок), он должен вызвать функцию обработчика.

Важно понимать (хотя в данном конкретном случае это довольно очевидно), что функцияне беги в этот момент. Это будет только бежатьпотомкогда это событие произойдет. Выполнение продолжается, как только среда выполнения подтверждает«Я буду запускать (или« перезвонить », отсюда и название« обратный вызов »), когда это произойдет. ЕслиsomeMoreCode() пытается получить доступclicks, это будет0не1.

Это то, что называетсяасинхронность, поскольку это то, что произойдет вне текущего потока выполнения.

Раздел 2: Зачем это нужно, или почему вымирают синхронные API?

Теперь важное соображение. Предположим, чтоsomeMoreCode() на самом деле очень долго работающий кусок кода. Что произойдет, если событие щелчка произошло, пока оно еще запущено?

В JavaScript нет концепции прерываний. Среда выполнения увидит, что выполняется код, и поместит вызов обработчика событий в очередь.Обработчик не будет выполнен раньшеsomeMoreCode() заканчивается полностью.

Хотя обработчик события щелчка является экстремальным в том смысле, что щелчок не гарантируется, это объясняетпочему вы не можете дождаться результата асинхронной операции, Вот пример, который не будет работать:

element.addEventListener("click", function(e) {
  console.log("Oh hey, I'm clicked!");
  clicks += 1;
});
while(1) {
  if(clicks > 0) {
    console.log("Oh, hey, we clicked indeed!");
    break;
  }
}

Вы можете нажать на содержание вашего сердца, но код, который будет увеличиватьсяclicks терпеливо ждет окончания (не завершающегося) цикла. К сожалению.

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

Вот почему асинхронная обработка применяется к другому классу вызовов, которые:

требует выполнения, а не JS, чтобы что-то делать (например, доступ к диску / сети)гарантированно прекратить (будь то в случае успеха или неудачи)

Давайте рассмотрим классический пример: вызовы AJAX. Предположим, мы хотим загрузить файл с URL.

Предположим, что в нашем текущем соединении среда выполнения может запрашивать, загружать и обрабатывать файл в форме, которую можно использовать в JS за 100 мс.С другой стороны, это немного хуже, это займет 500 мс.И иногда соединение действительно плохое, поэтому время выполнения будет ждать 1000 мс и сдается с таймаутом.

Если бы мы подождали, пока это не закончится, у нас будет переменная, непредсказуемая и относительно длительная задержка. Из-за того, как работает ожидание JS, все другие обработчики (например, пользовательский интерфейс) не будут выполнять свою работу в течение этой задержки, что приведет к зависанию страницы.

Звучит знакомо? Да, именно таксинхронный XMLHttpRequest работает, Вместоwhile(1) Цикл в коде JS, это по существу происходит в коде времени выполнения - поскольку JavaScript не может позволить другому коду выполняться во время ожидания.

Да, это допускает знакомую форму кода:

var file = get("http://example.com/cat_video.mp4");

Но за ужасную, ужасную цену все замерзает.Стоимость настолько ужасна, что современные браузеры считают ее устаревшей. Вотобсуждение темы на MDN.

Теперь давайте посмотрим наlocalStorage, Он соответствует описанию «завершение вызова во время выполнения», и все же он является синхронным. Зачем?

Проще говоря:исторические причины (это очень старая спецификация).

Хотя это, безусловно, более предсказуемо, чем сетевой запрос,localStorage по-прежнему нужна следующая цепочка:

JS code <-> Runtime <-> Storage DB <-> Cache <-> File storage on disk

Это сложная цепочка событий, и весь движок JS должен быть остановлен для этого. Это ведет кчто считается неприемлемым исполнением.

Теперь API Chrome изначально созданы для повышения производительности. Вы все еще можете увидеть некоторые синхронные звонки встаршая API, такие какchrome.extensionи есть вызовы, которые обрабатываются в JS (и поэтому имеют смысл как синхронные), ноchrome.storage является (относительно) новым.

Как таковой, этовключает в себя парадигму «Я подтверждаю ваш звонок и вернусь с результатами, а пока что сделаю что-то полезное» если есть задержка, связанная с выполнением чего-либо со временем выполнения. Синхронных версий этих вызовов нет, в отличие от XMLHttpRequest.

Цитирование документов:

Это [chrome.storage] асинхронный с массовыми операциями чтения и записи, и, следовательно,быстрее, чем блокировка и последовательный localStorage API.

Раздел 3: Как принять асинхронность?

Классическим способом борьбы с асинхронностью являются цепочки обратных вызовов.

Предположим, у вас есть следующий синхронный код:

var result = doSomething();
doSomethingElse(result);

Предположим, что сейчасdoSomething асинхронный Тогда это становится:

doSomething(function(result) {
  doSomethingElse(result);
});

Но что, если это еще сложнее? Скажи, что это было:

function doABunchOfThings() {
  var intermediate = doSomething();
  return doSomethingElse(intermediate);
}

if (doABunchOfThings() == 42) {
  andNowForSomethingCompletelyDifferent()
}

.. В этом случае вам нужно двигатьсявсе это в обратном вызове.return вместо этого должен стать вызов.

function doABunchOfThings(callback) {
  doSomething(function(intermediate) {
    callback(doSomethingElse(intermediate));
  });
}

doABunchOfThings(function(result) {
  if (result == 42) {
    andNowForSomethingCompletelyDifferent();
  }
});

Здесь у вас есть цепочка обратных вызовов:doABunchOfThings звонкиdoSomething немедленно, который заканчивается, нонекоторое время спустя звонкиdoSomethingElseрезультат которого подается наif через другой обратный вызов.

Очевидно, что это может привести к беспорядку.Ну, никто не сказал, что JavaScript - хороший язык. Добро пожаловать вCallback Hell.

Есть инструменты, чтобы сделать его более управляемым, напримеробещания, Я не буду обсуждать их здесь (не хватает места), но они не меняют основную часть «этот код будет выполняться только позже».

Секция TL; DR: мне абсолютно необходимо, чтобы хранилище было синхронным, хелп!

Иногда есть законные причины иметь синхронное хранилище. Например,webRequest API блокировка звонков не может ждать. Или Callback Hell будет стоить вам дорого.

Что вы можете сделать, это синхроннокэш асинхронногоchrome.storage, Это связано с некоторыми затратами, но это не невозможно.

Рассматривать:

var storageCache = {};
chrome.storage.sync.get(null, function(data) {
  storageCache = data;
  // Now you have a synchronous snapshot!
});
// Not HERE, though, not until "inner" code runs

Если вы можете поместить ВСЕ свой код инициализации в одну функциюinit()тогда у вас есть это:

var storageCache = {};
chrome.storage.sync.get(null, function(data) {
  storageCache = data;
  init(); // All your code is contained here, or executes later that this
});

По временному коду вinit() выполняет, а потомкогда любое событие, которое было назначено обработчиками вinit() происходит, storageCache будет заселен. Вы уменьшили асинхронность до ОДНОГО обратного вызова.

Конечно, это только снимок того, что хранилище смотрит во время выполненияget(), Если вы хотите сохранить согласованность с хранилищем, вам нужно настроить обновления наstorageCache с помощьюchrome.storage.onChanged События, Из-за JS-цикла с единичными событиями это означает, что кэш будет обновляться только тогда, когда ваш код не выполняется, но во многих случаях это приемлемо.

Точно так же, если вы хотите распространять изменения вstorageCache в реальное хранилище, просто установивstorageCache['key'] недостаточно. Вам нужно будет написатьset(key, value) шим что ОБА пишетstorageCache и планирует (асинхронный)chrome.storage.sync.set.

Реализация их остается в качестве упражнения.

 Zig Mandel20 июл. 2016 г., 07:19
Хотя асинхронный случай мог бы работать, будет почти невозможно также обрабатывать ситуации с ошибками, которые может возвращать API-интерфейс хранилища, в частности, ограничения скорости в API-интерфейсе синхронизации встречаются не так уж редко.
 Pimp Trizkit08 авг. 2017 г., 21:17
Замечательный ответ, даже если ответ нет. Я нашел это, положив толькоinit() кода в обратном вызове недостаточно. Я положу весь сценарий содержания там. В основном, загрузите кеш, а затем приступайте к работе. Затем, как вы упомянули, держите его в курсеonChange События. Тогда, пока вы всегда используетеstorageCache вы получите мгновенный доступ для чтения / записи. И тогда обычно «синхронная» сторона становится практически неактуальной. Это случается всякий раз, когда кто заботится. Так что, если ваш пользователь не нажимает кнопку PageAction в то же время, когда ваш скрипт контента меняет хранилище ... все должно быть в порядке.

вы получите источник странных ошибок. Сообщения выполняются асинхронно, что означает, что когда вы отправляете сообщение, остальная часть вашего кода может выполняться до того, как вернется асинхронная функция. На это нет гарантии, поскольку chrome является многопоточным, а функция get может задерживаться, т. Е. Hdd занят. Используя ваш код в качестве примера:

var a;
window.onload = function(){
    chrome.storage.sync.get({"disableautoplay": true}, function(e){
    a = e.disableautoplay;
});
}

if(a)
   console.log("true!");
else
   console.log("false! Maybe undefined as well. Strange if you know that a is true, right?");

Так что будет лучше, если вы используете что-то вроде этого:

chrome.storage.sync.get({"disableautoplay": true}, function(e){
    a = e.disableautoplay;
    if(a)
      console.log("true!");
    else
      console.log("false! But maybe undefined as well");
});

Если вы действительно хотите вернуть это значение, используйте API хранилища javascript. Здесь хранятся только строковые значения, поэтому вы должны приводить значение перед сохранением и после его получения.

//Setting the value
localStorage.setItem('disableautoplay', JSON.stringify(true));

//Getting the value
var a = JSON.stringify(localStorage.getItem('disableautoplay'));
 Kyle Hickey18 июл. 2016 г., 17:01
Спасибо, зе. Я собирался использовать LocalStorage, но я действительно хотел использовать хранилище синхронизации Chrome, если это возможно. Я думаю, мне придется

Ваш ответ на вопрос