Javascript-форум (https://javascript.ru/forum/)
-   Angular.js (https://javascript.ru/forum/angular/)
-   -   Angular 6, rxjs, Обсерверы и Обсервируемые (https://javascript.ru/forum/angular/74272-angular-6-rxjs-observery-i-observiruemye.html)

Nelkor 26.06.2018 13:24

Angular 6, rxjs, Обсерверы и Обсервируемые
 
Всем привет!
Пишу Hello-World приложение на Angular, используя библиотеку socket.io. Официальных руководств не нашел, так что информацию брал просто из интернета. Ключевые файлы в проекте следующие:

websocket.service.ts
import { Injectable } from '@angular/core';
import * as io from 'socket.io-client';
import { Observable, Subject } from 'rxjs';
 
@Injectable()
export class WebsocketService {
  private host = 'localhost:5000';
  private socket;
 
  constructor() {}
 
  connect(): Subject<MessageEvent> {
  this.socket = io(this.host);
 
  const observable = new Observable(observer => {
    this.socket.on('message', (data) => {
      console.log("Данные пришли с сервера");
      observer.next(data); // Я вызываю next, но данные отправляются не на сервер, а подписчику
    })
  });
 
  const observer = {
    next: (data: Object) => { // next отправляет данные на сервер
      console.log('Отправка данных на сервер...');
      this.socket.emit('message', JSON.stringify(data));
    },
  };
 
  return Subject.create(observer, observable);
  }
}


chat.service.ts
import { Injectable } from '@angular/core';
import { WebsocketService } from './websocket.service';
import { Observable, Subject } from 'rxjs';
import { map } from 'rxjs/operators';
 
@Injectable()
export class ChatService {
  messages: Subject<any>;
 
  constructor(private wsService: WebsocketService) {
    this.messages = wsService.connect();
  }
 
  sendMsg(msg) {
    this.messages.next(msg);
  }
}


app.component.ts
import { Component, OnInit } from '@angular/core';
import { ChatService } from './chat.service';
 
@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit{
 
  constructor(private chat: ChatService){ }
 
  ngOnInit() {
    this.chat.messages.subscribe(msg => {
      console.log('Данные из подписки:');
      console.log(msg);
    });
  }
 
  sendMessage() {
    this.chat.sendMsg("Test Message");
  }
}


Следует отметить, что всё работает. Но почему работает - не ясно :no:.

Конкретнее:
В websocket-сервисе определён объект observer с методом next. Его работа - отправлять сообщения на сервер. Этому методу подошло бы другое имя, но присвоить ему другое имя нельзя - возникает ошибка. Впрочем, ладно, это может быть связано с Subject.create. Дело-то в другом:
const observable = new Observable(observer => {
    this.socket.on('message', (data) => {
        console.log("Данные пришли с сервера");
        observer.next(data); // Я вызываю next, но данные отправляются не на сервер, а подписчику
    })
});


При получении сокетом сообщения, вызывается observer.next. Это тот же самый observer.next? Если да - почему он отправляет данные не на сервер, а подписчику? Если нет - откуда он берётся и почему имеет имя уже существующего элемента и вносит неразбериху в код?

Понятно, что он и должен отправлять данные подписчику по логике приложения. Я не хочу пинговать сервер бесконечным потоком сообщений. Но я хочу понять, почему это делается именно методом observer.next.

Взять, например, тот же chat-сервис:
sendMsg(msg) {
    this.messages.next(msg);
}


Функция sendMsg использует метод next для отправки сообщения на сервер.

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

destus 26.06.2018 13:44

Цитата:

Это тот же самый observer.next?
Нет. Это тот observer, который где-то в коде вызвал метод connect и соответственно подписался на получение уведомлений. Никакого отношения к socket.io он не имеет - это чисто rxjs сущность.
Цитата:

Если нет - откуда он берётся
из замыкания
Цитата:

Может быть есть официальная документация на этот счет?
https://www.learnrxjs.io/

Nelkor 26.06.2018 14:56

Спасибо!

Nelkor 26.06.2018 17:01

Впрочем, всё равно есть непонятный момент:

this.chat.messages.subscribe(msg => {
    console.log('Данные из подписки:');
    console.log(msg);
});


console.log подписан на this.chat.messages

sendMessage() {
    this.chat.sendMsg("Test Message");
}


sendMsg юзает this.messages.next

Предполагается, однако, что при этом сообщение будет отправлено на сервер, а не подписчику. И ведь так и происходит. А почему?)

destus 26.06.2018 17:50

Nelkor,
Пока не разобраться в документации, так и будут вопросы появляться на каждый случай. Лучше потратить день-два и все встанет на свои места.

Nelkor 26.06.2018 18:03

С одной стороны - да. С другой - если Вы знаете ответ, то почему бы не сказать его ;)

Кроме того, обладая какими-то знаниями, изучать документацию легче, нежели с нуля.

destus 26.06.2018 18:17

this.messages = wsService.connect();

здесь в messages запишется Subject. Когда я пишу messages.next('Блаблабла'), то вызывается метод next вот такой
const observer = {
    next: (data: Object) => { // next отправляет данные на сервер
      console.log('Отправка данных на сервер...');
      this.socket.emit('message', JSON.stringify(data));
    },
  };

который и отправляет данные на сервер.
А вот эта конструкция
const observable = new Observable(observer => {
    this.socket.on('message', (data) => {
      console.log("Данные пришли с сервера");
      observer.next(data); // Я вызываю next, но данные отправляются не на сервер, а подписчику
    })
  });

срабатывает когда у меня где-то в коде есть messages.subscribe().
То есть в Subject можно как писать новые значения, так и подписываться на него. В первом случае вызывается метод next объекта Observer (первый аргумент в методе Subject.create), во втором - определенная мной Observable (второй аргумент в методе Subject.create).

Nelkor 26.06.2018 18:33

На самом деле стало понятнее :)
Спасибо!

xShift 27.06.2018 20:11

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


Часовой пояс GMT +3, время: 23:30.