1

У меня есть загрузочное расширение, которое взаимодействует с хромированной частью Firefox (т. Е. Даже до загрузки содержимого), и для некоторой проверки требуется query an SQLite database. Я бы предпочел вызов синхронизации. Но поскольку синхронный вызов плох с точки зрения производительности и может вызвать возможные проблемы с пользовательским интерфейсом, мне нужно сделать асинхронный вызов БД.Firefox Restartless Extension - использует ли цикл while хорошую стратегию ожидания?

Мой случай использования такой:

  • Сделать Асинхронный вызов базы данных
  • После завершения сделать дальнейшую обработку

Теперь, это может быть легко обрабатывается путем размещения «дальнейшей обработки» часть в handleCompletion часть executeAsync функция.

Но, я хочу, чтобы «дальнейшая обработка» выполнялась независимо от выполняемого оператора, т. Е. Этот поиск в БД может произойти или не произойти. Если это не так хорошо и хорошо, продолжайте. Если это нужно, мне нужно подождать. Итак, я использую стратегию на основе флага; Я установил флаг handleCompletionCalled в handleError & handleCompletion callback to true.

В дальнейшей обработке части, я делаю

while(handleCompletionCalled) { 
// do nothing 
} 

//further processing 

Является ли это хорошая стратегией или я могу сделать что-то лучше (я не хочу использовать наблюдатель и т.д. для этого, так как у меня много такие случаи во всем моем расширении, и мой код будет заполнен Наблюдателями)?

ответ

2

Использование цикла while для ожидания - это серьезная Bad Idea ™. Если вы это сделаете, результат будет заключаться в том, что вы повесите пользовательский интерфейс или, как минимум, задействуете использование ЦП через крышу, быстро используя свою петлю в несколько раз быстрее, чем это возможно.

Вопрос о асинхронном программировании заключается в том, что вы запускаете действие, а затем выполняет другую функцию, обратный вызов, после завершения операции или сбоя. Это либо позволяет вам запускать несколько действий, либо отказаться от обработки какой-либо другой части общего кода. В общем случае этот обратный вызов должен обрабатывать все действия, зависящие от завершения асинхронного действия. Функция обратного вызова сама по себе не должна включать код для выполнения другой обработки. После того, как он выполнил то, что должно произойти в ответ на завершение действия async, он может просто вызвать другую функцию, например doOtherProcessing().

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

function continueAfterAllDone(){ 
    if(task1Done && task2Done && task3Done && task4Done) { 
     //do more processing 
    }else{ 
     //Not done with everything, yet. 
     return; 
    } 
} 

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

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

В загрузочном надстройке вам, вероятно, потребуется использовать интерфейс nsITimer для реализации тайм-аута или таймера интервалов. Это необходимо, потому что в то время, когда вы запускаете свой код инициализации, возможно, что нет <window> (т. Е. Не может быть доступа к window.setTimeout()).

Если вы собираетесь реализовать ожидание какой-то другой задачи, вы можете сделать это что-то вроде:

const Cc = Components.classes; 
const Ci = Components.interfaces; 

var asyncTaskIsDone = false; 
var otherProcessingDone = false; 
// Define the timer here in case we want to cancel it somewhere else. 
var taskTimeoutTimer; 

function doStuffSpecificToResultsOfAsyncAction(){ 
    //Do the other things specific to the Async action callback. 
    asyncTaskIsDone = true; 
    //Can either call doStuffAfterOtherTaskCompletesOrInterval() here, 
    // or wait for the timer to fire. 
    doStuffAfterBothAsyncAndOtherTaskCompletesOrInterval(); 
} 

function doStuffAfterBothAsyncAndOtherTaskCompletesOrInterval(){ 
    if(asyncTaskIsDone && otherProcessingDone){ 
     if(typeof taskTimeoutTimer.cancel === "function") { 
      taskTimeoutTimer.cancel(); 
     } 
     //The task is done 
    }else{ 
     //Tasks not done. 
     if(taskTimeoutTimer){ 
      //The timer expired. Choose to either continue without one of the tasks 
      // being done, or set the timer again. 
     } 
     //}else{ //Use else if you don't want to keep waiting. 
     taskTimeoutTimer = setTimer(doStuffAfterBothAsyncAndOtherTaskCompletesOrInterval 
            ,5000,false) 
     //} 
    } 
} 

function setTimer(callback,delay,isInterval){ 
    //Set up the timeout (.TYPE_ONE_SHOT) or interval (.TYPE_REPEATING_SLACK). 
    let type = Ci.nsITimer.TYPE_ONE_SHOT 
    if(isInterval){ 
     type = Ci.nsITimer.TYPE_REPEATING_SLACK 
    } 
    let timerCallback = { 
     notify: function notify() { 
      callback(); 
     } 
    } 
    var timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); 
    timer.initWithCallback(timerCallback,delay,type); 
    return timer; 
} 

function main(){ 
    //Launch whatever the asynchronous action is that you are doing. 
    //The callback for that action is doStuffSpecificToResultsOfAsyncAction(). 

    //Do 'other processing' which can be done without results from async task here. 

    otherProcessingDone = true; 
    doStuffAfterBothAsyncAndOtherTaskCompletesOrInterval(); 
} 

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

В одном из моих надстроек у меня есть разумная обработка, которая должна быть выполнена, но которая не является абсолютно необходимой для пользовательского интерфейса Firefox, который будет отображаться для пользователя. [См. «Performance best practices in extensions».] Таким образом, чтобы не задерживать пользовательский интерфейс, я использую таймер и обратный вызов, который выполняется через 5 секунд после запуска Firefox. Это позволяет пользовательскому интерфейсу Firefox чувствовать себя более восприимчивым к пользователю. Код, который:

const Cc = Components.classes; 
const Ci = Components.interfaces; 

// Define the timer here in case we want to cancel it somewhere else. 
var startupLaterTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); 

function startupLater(){ 
    //Tasks that should be done at startup, but which do not _NEED_ to be 
    // done prior to the Firefox UI being shown to the user. 
} 

function mainStartup(){ 
    let timerCallback = { 
     notify: function notify() { 
      startupLater(); 
     } 
    } 
    startupLaterTimer = startupLaterTimer.initWithCallback(timerCallback,5000 
                  ,Ci.nsITimer.TYPE_ONE_SHOT); 
} 

Обратите внимание, что то, что делается в startupLater() не, обязательно включают в себя все, что необходимо до проведения рекламы на активироваться пользователем в первый раз. В моем случае это все, что нужно сделать до того, как пользователь нажмет кнопку пользовательского интерфейса надстройки или вызовет ее через контекстное меню. Тайм-аут может/должен быть длиннее (например, 10 секунд), но составляет 5 с, поэтому мне не нужно так долго ждать тестирования во время разработки. Обратите внимание, что есть также одноразовые/запускаемые задачи, которые могут/должны выполняться только после того, как пользователь нажал кнопку пользовательского интерфейса надстройки.

1. Общая проблема программирования здесь: на некоторых языках программирования, если вы никогда не отдаете процессор из вашего основного кода, ваш обратный вызов никогда не может быть вызван. В таком случае вы просто запираетесь в петле while и никогда не выходите.

 Смежные вопросы

  • Нет связанных вопросов^_^