Я знаю, что функция обратного вызова работает асинхронно, но почему?

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

рассмотрим простой асинхронный ввод-вывод в узле.js

 var fs = require('fs');
 var path = process.argv[2];

  fs.readFile(path, 'utf8', function(err,data) {
   var lines = data.split('n');
   console.log(lines.length-1);
  });

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

Это не конкретный вопрос о node.js, речь идет об общей концепции обратного вызова на каждом языке программирования.

изменить:

вероятно, пример, который я привел, здесь не лучший. Поэтому давайте не будем рассматривать этот узел.фрагмент кода js. Я спрашиваю вообще - что делает трюк, который программа продолжает выполнять, когда функция обратного вызова encounter. Что такое синтаксис это делает концепцию обратного вызова неблокирующей?

спасибо заранее!

3 ответов


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

setTimeout(function(){
    console.log("this is async");
}, 100);

или он может быть синхронным, например:

an_array.forEach(function(x){
    console.log("this is sync");
});

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

вы также можете написать тест, чтобы узнать, если документация не доступно:

var t = "this is async";
some_function(function(){
    t = "this is sync";
});

console.log(t);

как работает асинхронный код

Javascript, как таковой, не имеет функции для асинхронного выполнения функций. Если вы хотите написать асинхронную функцию, у вас есть два варианта:

  1. используйте другую асинхронную функцию, такую как setTimeout или веб-работники для выполнения вашей логики.

  2. писать ее в с.

как для как C закодировал функции (как setTimeout) реализовать асинхронное выполнение? Все это связано с циклом событий (или в основном).

Цикл Событий

внутри веб-браузера есть этот кусок кода, который используется для создания сетей. Первоначально сетевой код мог загружать только одну вещь: саму HTML-страницу. Когда Мосиак изобрел <img> тег сетевой код эволюционировал для загрузки нескольких ресурсов. Затем реализованы в Netscape прогрессивный рендеринг картинки, они должны были сделайте сетевой код асинхронным, чтобы они могли рисовать страницу до загрузки всех изображений и обновлять каждое изображение постепенно и индивидуально. Это источник цикла событий.

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

на select() функция в C позволяет ждать нескольких операций ввода-вывода в одном потоке без необходимости создания дополнительных потоков. select() выглядит примерно так:

select (max, readlist, writelist, errlist, timeout)

чтобы он ждал ввода-вывода (из сокета или диска), вы бы добавили файловый дескриптор в readlist и оно возвратит когда данные доступные на любом из ваших каналов и/О. После его возвращения вы можете продолжить обработку данных.

интерпретатор javascript сохраняет ваш обратный вызов, а затем вызывает и есть. Интерпретатор ведет список всех тайм-аутов и вычисляет, что ему нужно передать как timeout для select(). Тогда когда select() возвращает в дополнение к выяснению, есть ли какие-либо обратные вызовы, которые должны быть вызваны из-за операции ввода-вывода интерпретатор также проверяет любые истекшие таймауты, которые должны быть вызваны.

так охватывает практически все функциональные возможности, необходимые для реализации асинхронных функций. Но современные браузеры также имеют веб-работников. В случае веб-работников браузер порождает потоки для асинхронного выполнения кода javascript. Для обратной связи в основной поток работники должны по-прежнему взаимодействовать с циклом событий (


обратный вызов не обязательно является асинхронным. Исполнение полностью зависит от того, как fs.readFile решает обработать параметр функции.

в JavaScript вы можете выполнять функцию асинхронно, используя, например,setTimeout.

Обсуждение и ресурсы:

как узел.JS реализует неблокирующий ввод-вывод?

модель и событие параллелизма Петля

Википедия:

существует два типа обратных вызовов, различающихся тем, как они управляют потоком данных во время выполнения:блокирование вызовов (также известный как синхронные вызовы или вызовы) и отложенные вызовы (также известный как асинхронные вызовы).


прежде всего, если что-то не асинхронно, это означает, что оно блокируется. Таким образом, бегун javascript останавливается на этой строке, пока эта функция не закончится (это то, что сделал бы readFileSync).

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

Я надеюсь, это решит ваши сомнения.