Как Mocha знает, ждать и таймаута только с мои асинхронные тесты?

Когда я тестирую Mocha, у меня часто есть комбинация асинхронных и синхронных тестов, которые нужно запустить.

Mocha обрабатывает это прекрасно, позволяя мне указать обратный вызов done, когда мои тесты асинхронны.

Мой вопрос: как Mocha внутренне наблюдает мои тесты и знает, что он должен ждать асинхронной активности? Кажется, я жду в любое время, когда у меня есть параметр обратного вызова, определенный в моих тестовых функциях. Вы можете видеть в примерах ниже, первый тест должен быть тайм-аутом, второй должен продолжаться и заканчиваться до того, как user.save вызывает анонимную функцию.

// In an async test that doesn't call done, mocha will timeout.
describe('User', function(){
  describe('#save()', function(){
    it('should save without error', function(done){
      var user = new User('Luna');
      user.save(function(err){
        if (err) throw err;
      });
    })
  })
})

// The same test without done will proceed without timing out.
describe('User', function(){
  describe('#save()', function(){
    it('should save without error', function(){
      var user = new User('Luna');
      user.save(function(err){
        if (err) throw err;
      });
    })
  })
})

Это волшебство node.js? Это что-то, что можно сделать в любом Javascript?

Ответ 1

Это простая чистая магия Javascript.

Функции на самом деле являются объектами, и у них есть свойства (такие как количество параметров определяются с помощью функции).

Посмотрите, как this.async установлен в mocha/lib/runnable.js

function Runnable(title, fn) {
  this.title = title;
  this.fn = fn;
  this.async = fn && fn.length;
  this.sync = ! this.async;
  this._timeout = 2000;
  this._slow = 75;
  this.timedOut = false;
}

Изменения логики Mocha основаны на том, определена ли ваша функция с параметрами.

Ответ 2

То, что вы ищете, это свойство длины функции, которое может определить, сколько аргументов ожидает функция. Когда вы определяете обратный вызов с помощью done, он может сказать и обрабатывать его асинхронно.

function it(str, cb){
  if(cb.length > 0)
    //async
  else
    //sync
}

https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function/Length