Все авинальные обратные вызовы javascript? Если нет, то откуда я знаю, какие?

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

У меня создается впечатление, что в следующем сценарии я на самом деле не писал асинхронный код.

function addOne(value){
  value = value + 1;
  return value;
}

function simpleMap(values, callback){
  for(i = 0; i < values.length; i++){
    val = values[i];
    val = callback(val);
    values[i] = val;
  }
  return values;
}

newValues = simpleMap([1,2,3], addOne);

Однако, например, я знаю, что функции jQuery AJAX действительно асинхронны (не принимая во внимание promises, которые теперь доступны). Что делает jQuery AJAX асинхронным? Это так просто, что он включает запросы XHR, и в браузере все запросы XHR являются асинхронными?

У меня такой же вопрос для среды nodejs. Может ли что-то в node быть асинхронным, если оно включает в себя что-то вроде файла i/o, process.nextTick, setTimeout или setInterval? Почему, когда я делаю что-то вроде вызова базы данных с mongodb/mongoose, это асинхронно? Что происходит за кулисами, которые делают это так?

Являются ли асинхронные "ситуации" предопределенными средой? Или есть способ сделать одну собственную функцию по-настоящему асинхронной, не используя очень специфические функции среды (такие как xhr, файл io в node, process.nexttick и т.д.)?

Ответ 1

Мне любопытно, все ли обратные вызовы javascript асинхронны

Нет. Например, обратный вызов, используемый Array#sort, не является асинхронным и не используется String#replace.

Единственный способ узнать, является ли обратный вызов асинхронным, - это его документация. Как правило, те, которые включают запросы на внешние ресурсы (например, вызовы ajax), являются асинхронными, а другие могут быть или не быть.

Однако, например, я знаю, что функции jQuery AJAX действительно асинхронны...

Не обязательно, поскольку в настоящее время jQuery по-прежнему имеет флаг async, который вы можете установить false для принудительного синхронного запроса. (Это не очень хорошая идея, и они собираются удалить это, но вы можете. JQuery передает флаг в основной объект браузера, который обеспечивает синхронное/асинхронное поведение.)

Что делает jQuery AJAX асинхронным?

Браузер. В вызовах jQuery ajax используется объект XMLHttpRequest (или в определенных ситуациях, элемент script), по умолчанию используется асинхронная операция, предоставляемая браузером.

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

До недавнего времени, нет. В соответствии с 5-й редакционной спецификацией, язык JavaScript в основном молчал по всей концепции потоков и асинхронности; это было только тогда, когда вы попали в среду, в которой он появился. Единственный способ сделать что-то асинхронным - использовать функцию, предоставляемую хостом, например nextTick (или любую другую операцию, которая выполняется асинхронно) в NodeJS или setTimeout в браузерах.

В спецификации ECMAScript 6-го издания в июне 2015 года они ввели promises в язык. Обратные вызовы подключены к обещанию ES6 через then, и такие всегда вызываются асинхронно (даже если обещание уже установлено при обратном вызове), и поэтому JavaScript теперь имеет асинхронность на уровне языка. Поэтому, если вы реализуете свою функцию так, чтобы она возвращала обещание, а не принимала обратный вызов, вы узнаете, что обратные вызовы then, подключенные к нему, будут запускаться асинхронно.

Ответ 2

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

Этот код, например, определяет функцию "addKeyHandler", которая является асинхронной. Но это работает только потому, что document.onKey называется асинхронным движком JS. Механизм JavaScript может обеспечивать асинхронную функциональность, поскольку операционная система предоставляет такую ​​функциональность, которая затем используется JS. ОС, в свою очередь, может обеспечивать только асинхронную функциональность, поскольку аппаратное обеспечение предоставляет ее (называемые аппаратными прерываниями).

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

var keyCallbacks = [];

var addKeyHandler = function(f) {
  keyCallbacks.push(f);
};

document.onkeypress = function(e) {
  keyCallbacks.forEach(function(f) {
      f(e);
  });
};

addKeyHandler(function(e) {
    console.log(String.fromCharCode(e.charCode));
});

Ответ 3

Обратные вызовы, которые вы называете собой, являются регулярными вызовами функций, которые всегда синхронны.

Некоторые собственные API-интерфейсы (например, AJAX, геолокация, Node.js или сетевые API) являются асинхронными и будут выполнять свои обратные вызовы позже в цикле событий.

Если вы вызываете обратный вызов синхронно из асинхронного обратного вызова, он также будет асинхронным.

Ответ 4

Простое выполнение обратного вызова не делает функцию асинхронной. Существует множество примеров функций, которые принимают аргумент функции, но не являются асинхронными, например Array forEach.

Для функции, которая должна быть асинхронной, ей необходимо выполнить асинхронную операцию. Способы введения асинхронности могут быть

  • функции таймера setTimeout, setInterval
  • специальные функции nextTick, setImmediate
  • выполнение ввода-вывода (прослушивание сети, запрос базы данных, чтение или запись с ресурса)
  • подписка на событие

Согласно статье "Выполняет ли обратный вызов функцию асинхронную?"