Почему некоторые синхронные библиотеки в nodejs придерживаются обратного вызова?

#node.js

#node.js

Вопрос:

Я новый разработчик nodejs, и я думаю, что разбираюсь в дизайне nodejs.

Я могу понять, что некоторые библиотеки, связанные с системным вызовом, должны быть асинхронными. Эти задания будут поставлены в очередь и обработаны в другом пуле потоков, и уведомлены через обратный вызов, когда оно завершится.

Однако я не могу понять, почему некоторые библиотеки, не связанные с системными вызовами, используют обратный вызов в качестве метода связи. Например, библиотека xml2js написана на Javascript, и, по-видимому, нет причин, по которым эта функция синтаксического анализа вернет статус через обратный вызов. Это может возвращать результат обработки напрямую, и читаемость кода будет повышена.

Мой вопрос в том, есть ли какая-либо причина, по которой некоторые разработчики библиотек nodejs придерживаются обмена данными на основе обратного вызова вместо того, чтобы просто использовать возвращаемое значение?

Комментарии:

1. Смотрите это в связи с проблемой xml2js github.com/Leonidas-from-XIV/node-xml2js/issues/47

Ответ №1:

В стиле обратного вызова нет ничего плохого.

 var return = doSomething();
...

doSomething(function(return) {
    ...
});
  

Это предпочтение. Они оба допустимы. Первое кажется «лучше» только потому, что вы к нему привыкли.

Одна из веских причин последнего заключается в том, что API не должен меняться, когда вы меняете свою библиотеку на неблокирующую.

Людям нужно напомнить, что node — это низкоуровневая неблокирующая библиотека ввода-вывода. Если вы собираетесь сделать что-то вроде js2xml, то, очевидно, вы ждете, когда node 0.6 стандартизирует API подпроцесса web worker, чтобы вы могли передать тяжелую работу подпроцессу и выполнять фактическую тяжелую работу неблокирующим способом.

Чтобы сделать это неблокирующим образом, ваш API должен быть асинхронным (или вам нужно встроить его в язык).

Ответ №2:

Если это не асинхронно, нет причин использовать обратный вызов для передачи возвращаемого значения.

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

Ответ №3:

На самом деле с точки зрения реализации анализатора LibXML. Вы уверены, что никогда не выполняется ввод-вывод на системном уровне?

Подумайте о сценарии, в котором анализируемый вами XML содержит DTD или схему. Как насчет обработки XInclude, которая часто выполняется в XML-анализаторах.

Хотя нет фундаментальной причины иметь API, который не использует какие-либо низкоуровневые функции ввода-вывода для использования стиля асинхронного обратного вызова, вы не всегда знаете, нет ли ситуаций, когда ввод-вывод действительно может иметь место.

Теперь предположим, что вы знаете, что ваш XML-анализатор не выполняет никакого ввода-вывода, потому что он не обрабатывает проверку XInclude и DTD / Schema. Поэтому, если вы решите пойти «традиционным» путем возврата значения, вы никогда не сможете реализовать обработку XInclude или проверку схемы без изменения вашего API.

Так часто, если вы пишете API, вам лучше использовать асинхронный / обратный вызов с самого начала, потому что вы никогда не знаете, что захотите сделать позже.

Ответ №4:

Обратные вызовы могут быть полезны в различных сценариях, например, когда вы перебираете некоторую коллекцию (которая по какой-то причине инкапсулирована):

 function Foo() {
    this._data = [1, 2, 3, 4, 5]; 
}

Foo.prototype.forEach = function(callback) {
    var i, 
        len = this._data.length;

    for(i = 0; i < len; i  ) {
        callback("Item number: "   this._data[i]);
    }
}

var foo = new Foo();

foo.forEach(function(item) {
    console.log(item);
});