Основная мотивация использования неблокирующего вызова заключается в том, что вы ожидаете возврата какого-либо внешнего процесса или устройства, поэтому вы освобождаете контроль над потоком, чтобы другие операции могли выполняться «пока вы ждете».
Поскольку неблокирующий / асинхронный код с использованием обратных вызовов труднее писать, читать и обслуживать, следует избегать неблокирующего кода, за исключением случаев, когда это будет иметь значение для производительности и масштабируемости вашего приложения или там, где это требуется с помощью API, который вы используете.
Рассмотрим этот относительно глупый пример:
function add(a,b,cb) { cb(a+b); }
console.log('2+2 is', add(2,2)); // -> 4
function add(a,b) { return a+b; }
add(2,2,function(sum) { console.log('2+2 is', sum); }); // -> 4
Первый из них немного проще для глаз.
Многие нодовые API имеют асинхронную версию, но не имеют синхронной версии. При использовании этих API будет очевидно, что вам нужно сделать свой код асинхронным.
В тех случаях, когда у вас есть выбор (например, при чтении файла), спросите себя: «Будет ли блокирующий вызов заставлять конечного пользователя ждать неоправданное количество времени?». Во время запуска приложения ответ обычно «нет», потому что этот код запускается только один раз, и у конечных пользователей не было возможности прикоснуться к серверу. Однако, если вы отвечаете на веб-запрос, то заставляя всех пользователей ждать исходящего вызова API или чтения с диска, это замедлит работу сайта для всех пользователей, тогда как неблокирующий вызов позволяет узлу продолжать обрабатывать новые запросы до тех пор, пока вы не получите данные. Запрошенный возвращается.