Используйте socket.io в разрешении для реализации одноразовых слушателей

Раньше я помещал одноразовых слушателей внутрь resolve. Следующий код может убедиться, что страница должна получить сообщение yes для разрешения x, затем "да еще раз" для разрешения y и т. д.:

app.config(['$stateProvider', function ($stateProvider) {
    $stateProvider
        .state('edit', {
            resolve: {
                x: ['$q', function ($q) {
                    var deferred = $q.defer();
                    $window.addEventListener("message", function (e) {
                        if (e.data === "yes") deferred.resolve(e.data)
                    }, { once: true };
                    return deferred.promise
                }],
                y: ... ...
                        if (e.data === "yes again") deferred.resolve(e.data)
                   ... ...
                    return deferred.promise
                }],
                z: ... ...
                    return deferred.promise

Теперь я хочу использовать socket.io для реализации слушателя; он прослушивает сообщения, отправляемые сервером. Если бы это было не в resolve, я бы использовал следующее для получения сообщений:

var socket = io.connect();
socket.on('message', function (message) {
   console.log(message)
})

Мне нужно получить один socket для одной страницы. Кто-нибудь знает, как поместить его в несколько resolve, чтобы добиться того, что сделали прослушиватели событий?


person SoftTimur    schedule 27.06.2017    source источник
comment
several resolve — похоже, вы хотите выполнить обещание более одного раза   -  person Jaromanda X    schedule 28.06.2017
comment
Я имею в виду разрешение обещания, затем разрешение другого обещания, затем разрешение еще одного обещания...   -  person SoftTimur    schedule 28.06.2017


Ответы (2)


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

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

Промисы просто не соответствуют архитектуре повторяющихся событий. Промисы — это одноразовые устройства, поэтому их следует использовать для представления одноразового события. Откройте файл, получите обещание, которое разрешается, когда этот файл теперь открыт. Сделайте конкретный http-запрос и получите обещание, которое разрешается с ответом на запрос.

person jfriend00    schedule 28.06.2017
comment
Спасибо за ваш комментарий... Я успешно использовал socket.once для имитации одноразового прослушивателя (см. мой ответ), с обещаниями, что это решение не слишком сильно меняет исходную структуру моего кода... - person SoftTimur; 29.06.2017

Я использую следующий код socket.once для имитации одноразового прослушивателя, пока работает без ошибок:

app.config(['$stateProvider', function ($stateProvider) {
    $stateProvider
        .state('edit', {
            resolve: {
                socket: [function () {
                    return io.connect();
                }],
                x: ['socket', '$q', function (socket, $q) {
                    var deferred = $q.defer();
                    socket.once("message", function (msg) {
                        if (msg.req === "yes") deferred.resolve(msg)
                    })
                    return deferred.promise
                }],
                y: ... ...
                        if (msg.req === "yes again") deferred.resolve(msg)
                   ... ...
                    return deferred.promise
                }],
                z: ... ...
                    return deferred.promise
person SoftTimur    schedule 29.06.2017
comment
Что происходит, когда msg.req !== "yes"? - person jfriend00; 29.06.2017
comment
Насколько я понимаю socket.once, если msg.req !== "yes", deferred никогда не будут разрешены, поэтому код будет висеть навсегда. Для меня это нормально, потому что я знаю порядок сообщений, мне просто нужно убедиться, что все сообщения перехвачены. Я предполагаю (я не пробовал), если я использую socket.on, а не socket.once, блок будет двигаться дальше, как только он получит msg, так что msg.req === "yes", msg не обязательно будут первым сообщением, которое получит блок... Надеюсь, socket.on разных блоков будут не вмешиваться в их дела... - person SoftTimur; 29.06.2017
comment
Я думаю, что лучше всего для каждого блока добавить слушателя с помощью socket.on, удалить слушателя, как только msg.req будет правильным, и двигаться дальше... Но я не знаю, как удалить самого слушателя внутри функции слушателя.. . - person SoftTimur; 29.06.2017
comment
Если вы используете одно и то же имя сообщения socket.io в разных блоках, вы не можете гарантировать, какое сообщение принадлежит какому обещанию, и это проблема надежности. Этот дизайн все еще кажется мне очень хлопотным, даже не видя более широкой картины того, что вы пытаетесь сделать. - person jfriend00; 29.06.2017