1 (изменено: dab00, 2014-03-03 13:42:47)

Тема: 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));  
}

Вопрос: сколько времени будет выполняться этот код?
Пока не выполнишь - не догонишь :
http://2.bp.blogspot.com/-3t8_AOMfZzM/UxQ-YBJbzfI/AAAAAAAACZg/ZbjWe-jDyLM/s1600/essay1.jpg

Догадались, в чем подвох?

Решение: перед удалением объекта не забыть завершить процессы, выполняющиеся асинхронно, для чего необходимо предусмотреть какой-нибудь механизм.

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 все должно завершиться примерно так:
http://2.bp.blogspot.com/-0FQ_7wyG0bc/UxRCSrgrZiI/AAAAAAAACZs/Cng_2-3DlJw/s1600/essay2.jpg

В общем памятуем об особенностях потока выполнения JavaScript.