it-swarm.com.ru

Как пользовательские события трансляции реализованы в JavaScript (или jQuery)?

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

То, что я имею в виду, выглядело бы следующим образом.

Во-первых, в разных местах кода будут операторы вида

some_subscriber.on_signal( 'some_signal', some_handler );

Я использую термин signal как сокращение для «события трансляции». В вышеприведенном выражении some_subscriber регистрируется как слушатель одного типа (называемый some_signal) таких сигналов, предоставляя обработчик для него.

В другом месте кода будут операторы вида

publisher.signal_types[ 'some_signal' ].broadcast( event_data );

Когда выполняются подобные операторы, генерируется новое событие и "broadcast". Под этим я подразумеваю, что код, который вызывает метод broadcast, не имеет прямой информации о слушателях для сигнала, который он выдает.


Я реализовал набросок этой идеи в этот jsFiddle , в основном, чтобы проиллюстрировать то, что я описал словами выше1, (Это, конечно, не производственный класс, и я не особенно уверен, что это можно сделать так.)

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

function make_publisher ( signal_types ) {

    // ...

    var _
    ,   signal = {}
    ,   ping = function ( type ) {
                   signal[ type ].broadcast( ... );
               }
    ;

    signal_types.forEach( function ( type ) {
                             signal[ type ] = $.register_signal_type( type );
                         } );

    return { signal_types: signal_types, ping: ping };
}

Этот объект издателя предоставляет только два элемента: типы передаваемых им сигналов (в signal_types) и метод ping. Когда вызывается его метод ping, издатель отвечает широковещание сигналом:

signal[ type ].broadcast( ... )

Конечные получатели этой трансляции нигде в этом коде не видно.

Во-вторых, в другом месте кода подписчики регистрируются как слушатели этих сигналов вещания, например, так

    $( some_selector ).on_signal( signal_type, some_handler );

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


Мой вопрос: есть ли лучший (или, по крайней мере, более стандартный) способ достижения этого эффекта «трансляции» пользовательских событий?

(Мне интересны как ответы на основе jQuery, так и ответы на вопросы "чистого JS".)


1Более ранняя злополучная версия этого поста была встречена с почти всеобщим непониманием и (конечно) слишком типичным понижением голосов. За одним исключением, все комментарии, которые я получил, оспаривали саму предпосылку поста, а один прямо ставил под сомнение мое понимание основ событийно-ориентированного программирования и т.д. Я надеюсь, что, представив рабочий пример того, что я имею в виду, по крайней мере это не будет так же невероятно, как когда я описывал это одними словами. К счастью, один полезный комментарий, который я получил в предыдущем сообщении, проинформировал меня о функции jQuery.Callbacks. Это был действительно полезный совет; реализация эскиза, упомянутая в посте, основана на jQuery.Callbacks.

8
kjo

Отлично.

Поэтому я думаю, что вы можете использовать собственные методы dispatchEvent и addEventListener и использовать document в качестве единственного элемента для публикация и подписка к этим событиям. Что-то вроде:

var myCustomEvent = new Event('someEvent');
document.dispatchEvent(myCustomEvent);
...
document.addEventListener('someEvent', doSomething, false);

И чтобы сделать кросс-браузер, вы могли бы:

var myCustomEvent = new Event('someEvent');
document.dispatchEvent(myCustomEvent);
...
if (document.addEventListener) {
    document.addEventListener('someEvent', doSomething, false);
} else {
    document.attachEvent('someEvent', doSomething);
}

Вы можете прочитать больше на эту тему здесь и здесь . Надеюсь это поможет.

13
Tahir Ahmed

Мой вопрос: есть ли лучший (или, по крайней мере, более стандартный) способ достичь этого эффекта «трансляции» пользовательских событий?

Нет, в Javascript нет более стандартного способа публикации/подписки. Он не встроен непосредственно в язык или браузер, и я не знаю стандартов для него.

У вас есть несколько вариантов (большинство из которых вы, кажется, знаете), чтобы собрать свою собственную систему вместе.

Вы можете выбрать определенный объект, такой как объект document или объект window, или новый объект, который вы создаете, и использовать .on() и .trigger() jQuery с этим объектом в качестве центрального центра обмена информацией, чтобы объединить модель публикации/подписки. Вы даже можете скрыть существование этого объекта от фактического использования, просто закодировав его в несколько служебных функций, если хотите.

Или, как вы, кажется, уже знаете, вы можете использовать функцию jQuery.Callbacks. Есть даже пример кода публикации/подписки в jQuery doc .

Или вы можете найти стороннюю библиотеку, которая предлагает несколько традиционную модель публикации/подписки.

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

2
jfriend00

Если вы пришли сюда в поисках способа jQuery, вот так:

Добавить трансляцию события/код отправки:  

Синтаксис:
$(<element-name>).trigger(<event-name>);

Пример: 

$.ajax({
    ...
    complete: function () {
        // signal to registered listeners that event has occured
        $(document).trigger("build_complete");
        ...
    }
});

Зарегистрировать слушателя на событие:  

Синтаксис:
$(<element-name>).on(<event-name>, function() {...}); 

Пример:

$(document).on("build_complete", function () {
    NextTask.Init();
});

Примечание: Делая это следующим образом: $(document).build_complete(function() {...}); приводит к ошибке: Uncaught TypeError: $(...).build_complete is not a function.

0
SNag