Публикация-подписка от начала читать исходный Node.js eventemitter

Node.js внешний интерфейс

предыдущая статьяКто первым выполнит setTimeout и setImmediate?Эта статья даст вам полное представление о цикле событий.Подробно объясняется асинхронный API браузера и Node.js, а также лежащий в его основе принцип Event Loop. В этой статье будет рассказано о том, как добиться асинхронных эффектов без использования нативного API, то есть режима публикации-подписки. Модель публикации-подписки также является высокочастотным тестовым сайтом в интервью.В этой статье будет реализована модель публикации-подписки сама по себе.Поняв ее принцип, мы можем читать Node.jsEventEmitterИсходный код, который также является типичной моделью публикации-подписки.

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

GitHub.com/Денис — см....

Зачем использовать модель публикации-подписки?

В отсутствиеPromiseРаньше мы часто использовали обратные вызовы при работе с асинхронными API, но если есть несколько асинхронных вызовов API, которые зависят друг от друга, слишком много уровней обратных вызовов может привести к «аду обратных вызовов». Следующий код демонстрирует, что если у нас есть три сетевых запроса, второй должен дождаться завершения первого, прежде чем его можно будет выдать, а третий должен дождаться завершения второго, прежде чем его можно будет выдать.Если мы используем обратные вызовы, станет вот так:

const request = require("request");

request('https://www.baidu.com', function (error, response) {
  if (!error && response.statusCode == 200) {
    console.log('get times 1');

    request('https://www.baidu.com', function(error, response) {
      if (!error && response.statusCode == 200) {
        console.log('get times 2');

        request('https://www.baidu.com', function(error, response) {
          if (!error && response.statusCode == 200) {
            console.log('get times 3');
          }
        })
      }
    })
  }
});

Поскольку ajax на стороне браузера будет иметь междоменные проблемы, я запустил приведенный выше пример с Node.js. В этом примере три слоя обратных вызовов, и мы уже немного закружились, если слоев будет больше, это будет действительно «ад».

модель публикации-подписки

Шаблон публикации-подписки — это шаблон проектирования, который используется не только в JS, этот шаблон может помочь нам решить «ад обратных вызовов». Его процесс показан ниже:

image-20200323161211669

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

В этом режиме нет необходимости попадать в «ад обратных вызовов» при работе с несколькими взаимозависимыми асинхронными API на фронте, нужно только подписаться на предыдущее сообщение об успехе и опубликовать сообщение после предыдущего успеха.

Реализуйте модель публикации-подписки самостоятельно

Зная принцип, давайте самостоятельно реализуем модель публикации-подписки, на этот раз для ее реализации воспользуемся классом ES6.Если вы не знакомы с объектно-ориентированным классом JS или классом ES6, прочитайте эту статью.:

class PubSub {
  constructor() {
    // 一个对象存放所有的消息订阅
    // 每个消息对应一个数组,数组结构如下
    // {
    //   "event1": [cb1, cb2]
    // }
    this.events = {}
  }

  subscribe(event, callback) {
    if(this.events[event]) {
      // 如果有人订阅过了,这个键已经存在,就往里面加就好了
      this.events[event].push(callback);
    } else {
      // 没人订阅过,就建一个数组,回调放进去
      this.events[event] = [callback]
    }
  }

  publish(event, ...args) {
    // 取出所有订阅者的回调执行
    const subscribedEvents = this.events[event];

    if(subscribedEvents && subscribedEvents.length) {
      subscribedEvents.forEach(callback => {
        callback.call(this, ...args);
      });
    }
  }

  unsubscribe(event, callback) {
    // 删除某个订阅,保留其他订阅
    const subscribedEvents = this.events[event];

    if(subscribedEvents && subscribedEvents.length) {
      this.events[event] = this.events[event].filter(cb => cb !== callback)
    }
  }
}

Решить ад обратного вызова

есть собственныйPubSub, мы можем использовать его для решения предыдущей проблемы с адом обратных вызовов:

const request = require("request");
const pubSub = new PubSub();

request('https://www.baidu.com', function (error, response) {
  if (!error && response.statusCode == 200) {
    console.log('get times 1');
    // 发布请求1成功消息
    pubSub.publish('request1Success');
  }
});

// 订阅请求1成功的消息,然后发起请求2
pubSub.subscribe('request1Success', () => {
  request('https://www.baidu.com', function (error, response) {
    if (!error && response.statusCode == 200) {
      console.log('get times 2');
      // 发布请求2成功消息
      pubSub.publish('request2Success');
    }
  });
})

// 订阅请求2成功的消息,然后发起请求3
pubSub.subscribe('request2Success', () => {
  request('https://www.baidu.com', function (error, response) {
    if (!error && response.statusCode == 200) {
      console.log('get times 3');
      // 发布请求3成功消息
      pubSub.publish('request3Success');
    }
  });
})

EventEmitter для Node.js

Node.jsEventEmitterИдея та же, что и в нашем предыдущем примере, но в ней больше обработки ошибок и больше API.Исходный код доступен на GitHub:GitHub.com/node будет /node…. Давайте рассмотрим несколько API:

Конструктор

Кодовый портал:GitHub.com/node будет /node…

image-20200323170909507

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

image-20200323171123339

EventEmitter.initОн также выполняет некоторую работу по инициализации.this._eventsнаписано с намиthis.eventsФункция та же самая, используется для хранения подписанных событий. Код ядра отмечен на схеме стрелками. Здесь следует отметить одну вещь: если есть только одна подписка на тип события,this._eventsЭто прямая функция, а не массив, в котором мы будем неоднократно видеть источник этого суждения, чтобы улучшить производительность записи.

Подписаться на события

Кодовый портал:GitHub.com/node будет /node…

EventEmitterAPI для подписки на события:onа такжеaddListener, из исходного кода мы видим, что эти два метода совершенно одинаковы:

image-20200323171656342

Оба метода называются_addListener, этот метод оценивает и обрабатывает ошибки в параметрах, а основной код по-прежнемуthis._eventsДобавить событие внутри:

image-20200323172045655

Опубликовать событие

Кодовый портал:GitHub.com/node будет /node…

EventEmitterAPI для публикации событийemit, этот API будет выполнять специальную обработку событий типа «ошибка», то есть выдавать ошибки:

image-20200323172657760

Если это не событие неправильного типа, удалите подписанное событие обратного вызова и выполните его:

image-20200323172822170

отписаться

Кодовый портал:GitHub.com/node будет /node…

EventEmitterAPI для отписки внутри:removeListenerа такжеoff, они абсолютно одинаковы.EventEmitterAPI отмены подписки не только удалит соответствующую подписку, но и выдастremoveListenerсобытия для уведомления внешнего мира. прямо здесь тожеthis._eventsвнутри соответствующегоtypeСудить, если есть только одно, то есть этоtypeТипfunction, ключ будет удален напрямую. Если подписок несколько, подписка будет найдена, а затем удалена. Если все подписки удалены, просто удалитеthis._eventsЗаглушка:

image-20200323174111868

Суммировать

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

  1. Решенный «ад обратного вызова»
  2. Разделение нескольких модулей, когда вы выполняете его самостоятельно, вам не нужно знать о существовании другого модуля, вам нужно только заботиться об опубликованных событиях.
  3. Поскольку несколько модулей могут не знать о существовании друг друга, события, о которых они заботятся, могут быть выпущены в очень дальнем углу, и вы не можете напрямую найти место, где события выпускаются с помощью переходов кода, что может быть немного сложно отлаживать. .

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

Добро пожаловать, чтобы обратить внимание на мой общедоступный номербольшой фронт атакиПолучите высококачественные оригиналы впервые~

Цикл статей "Передовые передовые знания":nuggets.capable/post/684490…

Адрес GitHub с исходным кодом из серии статей «Advanced Front-end Knowledge»:GitHub.com/Денис — см....