Опыт и работа модуля EventEmitter3

React.js

предисловие

EventEmitter3модуль представляет собой оптимизированный высокопроизводительныйEventEmitter,а такжеEventEmitterпредставляет собой реализацию шаблона публикации/подписки с использованиемEventEmitterМы можем создавать собственные механизмы событий во внешнем коде.

EventEmitter3модули одновременноNodeJSа такжебраузер

использоватьEventEmitter3

Установить

npm install eventEmitter3 --save

Цитировать

var EE = new EventEmitter()
  , context = { foo: 'bar' };
 
function emitted() {
  console.log(this === context); // true
}

// 订阅
EE.once('event-name', emitted, context);    // 只订阅一次
EE.on('another-event', emitted, context);   // 持续订阅
EE.removeListener('another-event', emitted, context);   // 移除现有的订阅

Сан-операция

Инкапсулируйте синхронный код с помощью Promise/async&await

Когда мы пишем сложную логику, мы можем быть ограничены фреймворком, контекстом и инструментами, которые могут использовать только асинхронное кодирование.Чтобы улучшить читаемость кода планировщика транзакций, мы можем использовать EventEmitter + Promise + async&await для изменения основной логики код в Синхронный способ пишется в том же контексте, блок кода. Например, когда я использую React Hooks для написания некоторых сложных компонентов, поскольку функция обновления, возвращаемая useState, не предоставляет функцию обратного вызова, подтверждающую, что новое состояние было успешно отрисовано, как SetState компонента класса, я могу только сотрудничать с useEffect для обрабатывать сигнал завершения рендеринга. Но таким образом наш логический код будет вынужден разбиваться на несколько блоков кода, что приведет к чрезмерно сложному коду и ухудшению читабельности и удобства сопровождения, например следующий код:

function MyComponent() {
  const [size, setSize] = useState({
    width: 0,
    height: 0
  });
  useEffect(() => {
    // 在这里对 canvas 进行 draw 的操作才是安全的
  }, [size]);
  return (
    <div>
      <button onClick={() => {
        setSize({
          width: 100,
          height: 100
        });
        // 这里对 canvas 进行 draw 等操作可能不安全,因为此时 Size 变更后并没有实际应用到 dom 中,所以很可能会 draw 后 dom 中的 canvas 会重新渲染,而 canvas 重新渲染后其中绘制的内容会被重置。
      }}>init canvas</button>
      <canvas style={{ width: `${size.width}px`, height: `${size.height}px` }}></canvas>
    </div>
  )
} 

Далее давайте оптимизируем наш код:

const EE = new EventEmitter();

function MyComponent() {
  const [size, setSize] = useState({
    width: 0,
    height: 0
  });
  // 封装同步更新方法
  const setSizeSync = (value) => {
    setSize(value);
    return new Promise(resolve => {
      EE.once('onSizeChange', resolve);     // 订阅一次 "onSizeChange" 事件
    });
  }
  useEffect(() => {
    EE.emit('onSizeChange');    // 触发 "onSizeChange" 事件
  }, [size]);
  return (
    <div>
      <button onClick={async () => {
        await setSizeSync({
          width: 100,
          height: 100
        });
        // 现在这里可以安全的使用 CanvasContext 对 Canvas 进行操作了
      }}>init canvas</button>
      <canvas style={{ width: `${size.width}px`, height: `${size.height}px` }}></canvas>
    </div>
  )
}