Javascript websockets - контролировать начальное соединение/когда onOpen get bound
Два связанных вопроса, которые могут быть более укоренены в моей нехватке знаний о том, как/если браузеры предварительно анализируют javascript:
var ws = new WebSocket("ws://ws.my.url.com");
ws.onOpen = function() { ... };
Кажется, нет никакого способа напрямую контролировать инициализацию WebSocket
, после того, как она будет завершена в обратном вызове, поэтому я предполагаю, что соединение создается, как только загружается javascript-код и попадает в конструктор?
Когда свойство onOpen
привязано к ws
? Существует ли какая-либо вероятность состояния гонки (если по какой-то причине у вас был какой-то код между определением сокета и определением onOpen
?), Так что onOpen
неразрешимо связано до/после установления соединения (I знаете, вы могли бы проверить ws.readyState
). Дополнительным для этого является блокировка квитирования WebSocket?
Я понимаю весь проект на данный момент, возможно, зависимый от реализации, и я, возможно, пропустил что-то ослепительно очевидное, но я не мог видеть ничего особенного в моих интернет-поисках/просматривать черновик w3c, поэтому любая помощь в мое понимание работы websockets/javascript очень ценится!
Ответы
Ответ 1
JavaScript является однопоточным, что означает, что сетевое соединение не может быть установлено до тех пор, пока текущая область выполнения не завершится, и выполнение сети не получится запустить. Объем выполнения может быть текущей функцией (функция connect
в приведенном ниже примере). Таким образом, вы можете пропустить событие onopen
, если вы привязываетесь к нему очень поздно, используя setTimeout, например. в этом примере вы можете пропустить событие:
Вид: http://jsbin.com/ulihup/edit#javascript,html,live
код:
var ws = null;
function connect() {
ws = new WebSocket('ws://ws.pusherapp.com:80/app/a42751cdeb5eb77a6889?client=js&version=1.10');
setTimeout(bindEvents, 1000);
setReadyState();
}
function bindEvents() {
ws.onopen = function() {
log('onopen called');
setReadyState();
};
}
function setReadyState() {
log('ws.readyState: ' + ws.readyState);
}
function log(msg) {
if(document.body) {
var text = document.createTextNode(msg);
document.body.appendChild(text);
}
}
connect();
Если вы запустите пример, вы можете увидеть, что строка "onopen called" log никогда не выводится. Это потому, что мы пропустили это событие.
Однако, если вы сохраняете new WebSocket(...)
и привязку к событию onopen
в той же области исполнения, то нет никаких шансов, что вы пропустите событие.
Для получения дополнительной информации о scope of execution
и о том, как они поставлены в очередь, запланированы и обработаны, посмотрите сообщение Джона Ресига на Таймеры в JavaScript.
Ответ 2
@leggetter является правильным, следующий код выполняет последовательно:
(function(){
ws = new WebSocket("ws://echo.websocket.org");
ws.addEventListener('open', function(e){
console.log('open', e);
ws.send('test');
});
ws.addEventListener('message', function(e){console.log('msg', e)});
})();
Но в W3C spec есть любопытная строка:
Верните новый объект WebSocket и продолжите эти шаги в фоновом режиме (без блокировки скриптов).
Это меня сбивало с толку, когда я изучал браузер для него. Я предполагаю, что пользовательские агенты игнорируют это, или я неправильно интерпретирую его.
Ответ 3
Обратите внимание на то, что операции ввода-вывода могут выполняться в рамках исполнения.
Например, в следующем коде
var ws = new WebSocket("ws://localhost:8080/WebSockets/example");
alert("Hi");
ws.onopen = function(){
writeToScreen("Web Socket is connected!!" + "<br>");
};
function writeToScreen(message) {
var div = document.getElementById('test');
div.insertAdjacentHTML( 'beforeend', message );
}
появится сообщение "Web Socket is connected"
или нет, в зависимости от того, сколько времени вам потребовалось, чтобы закрыть оповещение "Hi"
Ответ 4
Никаких фактических операций ввода-вывода не произойдет, пока ваш script не завершит выполнение, поэтому не должно быть условия гонки.