Показать сообщение отдельно
  #26 (permalink)  
Старый 19.09.2018, 11:33
Аватар для Malleys
Профессор
Отправить личное сообщение для Malleys Посмотреть профиль Найти все сообщения от Malleys
 
Регистрация: 20.12.2009
Сообщений: 1,714

Та и не нашёл, где там модули! То, что вы запихнули файлы в папку `modules` и, о ужас, дописали к имени переменной "Module", конечно же не сделает из них ни каким автомагическим способом модули. (также они все глобальны у вас, но странности вида `const Chat = window.Chat;` тоже зачем-то встретились)



Чтобы указать входную точку для вашей программы, используйте атрибут type со значением module
<script src="/javascripts/main.js" type="module"></script>
И это единственное, что вам нужно указать в вашем html.

const chat = new Chat;
chat.init();
Так и представил, что было если было бы так:
const array = new Array;
array.init();
Так что почему бы не просто `const chat = new Chat;`?

Используйте стрелочные функции, тогда не придётся писать такое `const _t = this;`

Можно просто `event_name.constructor === String`
`this.socket.readyState === 1` WTF??? Почему не `this.socket.readyState === this.socket.OPEN` мне пришлось посмотреть в документации, что такое 1

У вас в SocketModule.prototype.readyStateConnection переменная timer всегда новая, так что старый таймер невожможно остановить

У вас в chat.js передается `path: options.socketPath`, но в socketModule.js не используется...

Вместо класса XMLHttpRequest можно использовать функцию fetch.

Ваш /api/connect может возвратить не только 200 но и 304 (может быть, у меня именно так и произошло), почему бы не проверять так `response.status >= 200 && response.status < 400`, или даже `response.ok` (если используете fetch)

`this.socket;`
почему бы не (однако это ужасно, кто знает как лучше?)
this.socket = {
	readyState: WebSocket.prototype.CLOSED
};
тогда не будет неожиданных ошибок связанных тем, что this.socket равен null Это и была главная причина!

Вот исправленный код, исправленный с учётом сказанного выше, и модули тоже используются (а не переменные с именем, содержащим "Module")

В index.html теперь только нужно, то что касается скриптов
<script src="/javascripts/main.js" type="module"></script>


main.js
import Chat from "./Chat.js";

document.addEventListener("DOMContentLoaded", () => {
	const chat = new Chat;
});


options.js Я использовал этот сервер для теста, у вас там должно быть что-то другое
export default {
	socketPath: "wss://echo.websocket.org"
};


Chat.js
import Socket from "./modules/socketModule.js";
import options from "./options.js";

export default class Chat {
	constructor() {
		this.transport = new Socket({
			path: options.socketPath
		});
		
		// FIXME в отдельный модуль это я проверил как оно работает если текст в текстовое поле ввести и отправить
		document.addEventListener("click", event => {
			if(event.target.matches("#send_message [type='submit']")) {
				event.preventDefault();
				
				this.transport.sendMessage('chat_message', {
					type: 'text',
					text: document.querySelector("[name='message_text']").value
				});
			}
		})
		
		this.transport.sendMessage('chat_message', {
			type: 'text',
			text: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit.'
		});
	}
}


modules/socketModule.js
export default class SocketModule {
	constructor({ path }) {
		this.socket = {
			readyState: WebSocket.prototype.CLOSED
		};
		this.connection();
		this.path = path;
	}
        
	connection() {
		this.checkServer(server => {
			if (!server) return;

			this.socket = new WebSocket(this.path);
			this.socket.addEventListener('open', () => {
				this.sendMessage('connection', {
					client: true
				});

				this.indicatorControl = true;
			});
			
			this.socket.addEventListener("message", event => {
				// FIXME логику разбора в отдельный модуль
				const { event_name, data } = JSON.parse(event.data);
				
				if(event_name === "chat_message") {
					var p = document.createElement("p");
					p.textContent = data.text;
					document.getElementById("messages").append(p);
				}
			});

			this.socket.addEventListener('close', () => {
				this.indicatorControl = false;
				this.connection();
			});
		});

		return this;
	}
	
	set indicatorControl(value) {
		// что-то делает
	}

	checkServer(callback) {
		let timer;
		let count = 0;

		timer = setInterval(function() {			
			fetch("/api/connect", {
				headers: {
					"Content-Type": "application/x-www-form-urlencoded"
				}
			}).then(response => {
				if(response.ok) {
					clearInterval(timer);
					callback(true);
				}
			});

			count++;

			if (count === this.reconnectCount) {
				clearInterval(timer);
				console.log('Превышен лимит ожидания!');
			}
		}, 200);

		return this;      
	}
        
	sendMessage(event_name, data) { // event_name (string), data (string, array, object)
		if (event_name.constructor === String) {
			this.readyStateConnection(() => {
				console.log(event_name, data);
				this.socket.send(JSON.stringify({ event_name, data }));
			});
		} else
			return;

		return this;
	}
        
	readyStateConnection(callback) {
		if (this.socket.readyState === this.socket.OPEN) {
			callback();
		} else {
			setTimeout(() => {
				this.readyStateConnection(() => callback());
			}, 0);
		}
	}
};


Но очень там не сердитесь, что я всё исправил на модули, как описано в стандарте JavaScript.

UPD В readyStateConnection всё-таки не нужно стирать таймер, а то сообщения отправленные до подключения не отправятся. Исправил код выше(modules/socketModule.js)

Последний раз редактировалось Malleys, 19.09.2018 в 12:31.
Ответить с цитированием