Тема: JavaScript. Небольшой этюд на тему неблокирующего кода
Задача: создать объект, который через определенные промежутки времени будет обновлять свои свойства или, к примеру, сообщать другим объектам о своем самочувствии. Вопрос: что может случиться, если "неправильно" этот самый объект удалить. По мотивам одного фэйла...
Сразу хочу предложить пару примеров на Node.js, браузерный код почти не отличается от изложенного ниже.
test1.js:
global.obj = new Obj(Date.now());
log('created');
setTimeout(function() {
delete global.obj;
log('deleted');
}, 15000);
function Obj(dt) {
this.dt = dt;
var self = this;
setInterval(function() {
self.dt = Date.now();
log();
}, 5000);
}
function log(s) {
console.log('global.obj %s: %s', s || '', JSON.stringify(global.obj));
}
test2.js:
global.obj = new Obj(Date.now());
log('created');
setTimeout(function() {
delete global.obj;
log('deleted');
}, 15000);
function Obj(dt) {
this.dt = dt;
var self = this;
(function schedule() {
setTimeout(function() {
self.dt = Date.now();
log();
schedule();
}, 5000);
}());
}
function log(s) {
console.log('global.obj %s: %s', s || '', JSON.stringify(global.obj));
}
Вопрос: сколько времени будет выполняться этот код?
Пока не выполнишь - не догонишь :
Догадались, в чем подвох?
Решение: перед удалением объекта не забыть завершить процессы, выполняющиеся асинхронно, для чего необходимо предусмотреть какой-нибудь механизм.
test3.js:
global.obj = new Obj(Date.now());
log('created');
setTimeout(function() {
clearInterval(global.obj.interval);
delete global.obj;
log('deleted');
}, 15000);
function Obj(dt) {
this.dt = dt;
var self = this;
this.interval = setInterval(function() {
self.dt = Date.now();
log();
}, 5000);
}
function log(s) {
console.log('global.obj %s:', s || '');
console.dir(global.obj);
}
test4.js:
global.obj = new Obj(Date.now());
log('created');
setTimeout(function() {
global.obj.interval = false;
delete global.obj;
log('deleted');
}, 15000);
function Obj(dt) {
this.dt = dt;
var self = this;
this.interval = true;
(function schedule() {
setTimeout(function() {
self.dt = Date.now();
log();
if (!self.interval) return;
schedule();
}, 5000);
}());
}
function log(s) {
console.log('global.obj %s:', s || '');
console.dir(global.obj);
}
После выполнения кода test3.js вывод в консоль получился довольно большой, потому как там имеют место циклические ссылки, поэтому целиком его не даю, а после выполнения test4.js все должно завершиться примерно так:
В общем памятуем об особенностях потока выполнения JavaScript.