2015-12-22 2 views
3

Я относительно новичок в Node.js и JavaScript-оправдании, если вопрос ниже тупой. Для меня обещания для асинхронной обработки имеют смысл, но я не уверен на 100% об использовании обещаний, когда дело доходит до последовательной/последовательной обработки. Давайте посмотрим на пример (псевдокод):Использование обещаний для последовательной обработки

Цель: прочитать файл, обработать то, что было прочитано из файла, и отправить уведомление с помощью HTTP post call.

bendUniverseWithoutPromise: function() { 

    var data = fs.readFileSync(..); //Read the file 
    var result = processData(data); 
    this.postNotification(data); 

} 

В приведенной выше функции processData() не может работать до тех пор, пока мы не прочитаем файл. И мы не можем отправить уведомление, пока не закончим обработку.

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

bendUniverseWithPromise: function() { 
     return new Promise(function() { 
     fs.readFileAsync(fileName) 
      .then(processData(data)) 
      .then(postNotification(result)) 
     })   
    } 

Теперь мои вопросы:

  1. Увидев, что нам требуется последовательная/последовательная обработка в этом случае, как версия обещания лучше, чем версия без обеда? Что он делает лучше, чем первый пример? Может быть, это плохой пример, но тогда что было бы хорошим примером для демонстрации различий?
  2. Помимо синтаксиса, версия обещания добавляет немного (только немного) в понятность читаемости кода и может усложниться с вложенными обещаниями, контекстом (это!) И т. Д.
  3. Я действительно понимаю, что технически первое метод НЕ будет возвращаться до тех пор, пока вся обработка не будет выполнена, а вторая немедленно вернется, а обработка, хотя и будет оставаться последовательной (в контексте метода), будет продолжена в фоновом режиме.
  4. Существует ли общее правило относительно использования обещаний? Существуют ли шаблоны и анти-шаблоны?

Благодарим вас заблаговременно.

+0

Одно хорошее правило: может потребоваться время, и пользователи подумают, что мое приложение не отвечает, или пользователи могут делать другие вещи во время выполнения этих действий? если так перейдите к async – Luizgrs

+0

Вы имели в виду 'this.postNotification (result);'? – Bergi

+0

Вы можете найти [эти эмпирические правила] (http://stackoverflow.com/a/25756564/1048572) занимательные – Bergi

ответ

1

Сначала давайте исправим асинхронный код:

bendUniverseWithPromise: function() { 
    return fs.readFileAsync(fileName) 
      .then(processData) 
      .then(postNotification); 
} 

Теперь, что выше был (почти, если бы она была завершена) анти-закономерность - explicit construction anti-pattern.

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

Примечание: fs.readFileAsync не возвращает обещание по умолчанию и должно быть «обещано».

+0

Я бы не назвал это явным конструктивным антипаттерном, когда он просто не работал. Не было никакого вызова 'resolve' вообще – Bergi

+0

@Bergi - Да, вы правы. Даже не заметил, что это не очень полезный код. – Amit

+0

... и все еще не используется код, проверьте ответ @ dape на исправленный снипп – Bergi

2

Я постараюсь ответить на все четыре ваших вопроса, взяв ваш пример дальше.

Скажем, первая операция (чтение файла) является медленной операцией ввода-вывода и занимает 900 мс. Обработка и уведомление связаны с привязкой к процессору и привязке ввода-вывода соответственно, занимая 50 мс каждый. What do the terms “CPU bound” and “I/O bound” mean?

Теперь обе версии будут принимать те же самые 1000 мс, чтобы закончить, но второй пример использует имеющиеся ресурсы лучше, поскольку это асинхронный.В этом и заключается преимущество версии на основе обещаний. Первая версия сделает сервер полностью безответственным в течение целой секунды, а вторая версия сделает сервер невосприимчивым во время этапа обработки привязки процессора 50 мс.

Это, надеюсь, станет еще более ясным, когда мы рассмотрим 10 из этих запросов, поступивших в то же время. Первый пример проходит через них по одному, обслуживая запрос № 1 после 1s, № 2 после 2 секунд и т. Д., Заканчивая после 10 секунд. Его средняя производительность составляет 1 рек/с. Вторая версия запустит файл, читаемый для запроса №1, затем сразу же начнет запрашивать # 2, разворачивает другой файл и т. Д. Для всех запросов. Затем все запросы завершали чтение в течение 1 с, предполагая 100 мс служебных данных и мало или вообще не насыщали пропускную способность чтения диска. Затем обработка будет стоять в очереди, общая сумма 500 мс для всех запросов. Наконец, мы могли выполнять проводку уведомлений параллельно, из-за этого снова был связан с I/O. Все запросы затем в этом идеализированном примере завершались примерно через 1,5 секунды с более чем 6 req/s, с увеличением производительности 6 раз. Это происходит исключительно из-за лучшей изобретательности, обеспечиваемой асинхронностью.

Правило поэтому, всегда использует асинхронные/обещания при выполнении операций ввода-вывода.


Sidenote:

Ваш второй пример не является правильным, как нет data или result переменная, определенная в этой области видимости, правильная версия будет проходить в только функции then().

bendUniverseWithPromise: function (fileName) { 
    return fs.readFileAsync(fileName) 
      .then(processData) 
      .then(postNotification)   
} 
+1

Думаю, вам нужно передать 'this.postNotification.bind (это)' хотя для сопоставления синхронного кода – Bergi

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