Pull to refresh

Comments 52

Вопрос №7. Почему в модулях переменные верхнего уровня не являются глобальными?

Думаю, что здесь не хватает дополнения о том, что чего это?

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

Да просто модули это одноразовые функции конструирующие объект :)


(function (exports, require, module, __filename, __dirname) {
// module code
})(the_module.exports, require, the_module, module_file_name, module_folder);

Разве что return не нужен.


Или вот еще ну очень упрощённое(без сохранения объектов и распутывания петель) представление функции require:


function require(file_name) {
    var module_text = fs.readFileSync(file_name, 'utf8'),
        module = new Module(...);
    (new Function ("exports", "require", "module", "__filename", "__dirname", module_text)) (module.exports, require, module, file_name, Path.dirname(file_name));
    return module.exports;
}
Однако, если вы пользуетесь синхронными методами внутри обработчиков неких событий, вроде коллбэка HTTP-сервера, отвечающего за обработку запросов, то это, без вариантов, совершенно неправильно. Делать так настоятельно не рекомендуется.

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

Вы заблокируете весь thread своим синхронным методом. А это значит, что весь JS вашего сервера на время чтения файла перестанет работать. Он будет ждать окончания чтения файла. А если у вас HTTP-сервер который должен обрабатывать множество соединений одновременно, то все эти соединения повиснут. Такое, разумеется, в большинстве случаев неприемлемо.

UFO just landed and posted this here
Стоп, чтение файла происходит же в колбеке обработчике события, а сам этот колбек должен аснхронно же выполняться.
Чтение файла происходит в отдельном потоке, который вызывает callback после завершения операции.

Видимо есть недоразумение.
Есть, например, функция fs.readFile и fs.readFileSync.
Вторая работает без callback и возвращает результат операции.
Именно вторая и блокирует основной поток выполнения.

Так же есть другие fs.*Sync функции
Я имелл ввиду колбек http запроса должен быть ассинхронным. Ведь если ты передаешь колбек в setTimeout он ассинхронный, если передаешь колбек в readFileSync, колбек тоже ассинхронно выполняется. Почему же когда ты передаешь колбек в http.createServer, то он выполняется синхронно, а ты вполне логично ожидаешь тут ассинхронности. Ну то есть ты ожидаешь, что весь код внутри колбека будет ассинхронно выполняться по отношению к внешнему коду.
нельзя передать callback в readFileSync

Среда выполнения — однопоточная (на самом деле нет, но программисту доступен только 1 поток). Если внутри callback асинхронной функции выполнить длительное синхронное действие (а чтение файла именно таким и может быть), то это заблокирует обработку всех остальных функций и они будут ждать своей очереди.

попробуйте выполнить что-то вроде
  setTimeout(() => {while (true) {}}, 0)


это приведет к тому, что функция-callback, которая передана в setTimeout, когда до нее дойдет очередь, заблокирует основной поток навсегда (ну, до принудительного прерывания).
Перепутал, имелл ввиду readFile. Но вы правы.
Честно говоря думал что следующие два куска кода эквивалентны:
setInterval(() => {
  let file = fs.readFileSync(
    '...', // путь к очень жирному файлу
    {encoding: 'utf8'});
}, 0);

и вот этот:
setInterval(async () => {
  let file = await new Promise((resolve, reject) => {
    fs.readFile(
      '...', // путь к очень жирному файлу
      {encoding: 'utf8'}, (err, data) => {
        resolve(data);
      });
    });
}, 0);

Но оказалось нет (
Оказывается даже вот такой код:
setInterval(async () => {
  let file = await new Promise((resolve, reject) => {
    let data = fs.readFileSync(
      '...', // путь к очень жирному файлу
      {encoding: 'utf8'});
    });

    resolve(data);
}, 0);

Работает как первый вариант, а не как второй выше, блокируя основной поток. Офигеть…

А что фигеть-то? Вам же сразу сказали: синхронные версии методов блокируют весь процесс целиком.

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

То, что он выполняется асинхронно, еще не означает что он выполняется в каком-то другом потоке кроме основного.

Уже разобрался эксперементируюя. Но вот открываю я доку ноды для readFile и readFileSync и там ни слова об этом.
nodejs.org/api/fs.html
In busy processes, the programmer is strongly encouraged to use the asynchronous versions of these calls. The synchronous versions will block the entire process until they complete--halting all connections.
Большое спасибо всем за разъяснения. Я теперь гораздо лучше понимаю этот момнет в ноде.

Не совсем понятна соль 4-го вопроса. Теперь я знаю, что node использует некую c-ares. И что мне с этим делать? Автор пишет, что:


система обучения Node выстроена неправильно

Ок. Теперь с осознанием того, что node использует c-ares всё поменялось? :)
P.S. ответы на большую часть вопросов знал.

Ну следующий логичный шаг — загуглить, что такое c-ares, и за что отвечает, не?

c-ares is a C library for asynchronous DNS requests (including name resolves)

Ух ты. NodeJS умеет асинхронные DNS запросы.
P.S. ушёл переписывать свой js-код под новые реалии

на один процесс Node приходится только один стек вызовов.
Точно на один процесс, а не на один поток?

Да, точно. Решения с несколькими потоками существуют — но обычно в процессе ноды всего 1 видимый программисту поток.

Ага. Но я немного о другом. Поток (он же поток выполнения?) всегда имеет call stack, а возможно еще какой-то state например для работы корутин. То есть стек вызовов привязан к потоку, а не к процессу. В общем то поток это «код + стек вызовов». Ну да ладно.

В разделении потоков и процессов с точки зрения языка Javascript на платформе Node.js нет никакого смысла: эти слова обозначают одно и то же. Потому что у каждого процесса ровно 1 видимый поток.

Нет, каждый активный инстанс WebWorker является отдельным нативным потоком со своим event loop.

А WebWorker на ноду уже завезли?

нативно — пока еще нет, а в виде расширений давно. Но учитывая, как оно работает в браузерах (в том же хроме), то нет оснований предполагать, что реализация в node.js будет существенно отличаться по своей сути.

Сколько потоков (V8 и libuv) в сумме запускается в node.js процессе? Зависит ли это от ОС?

В v8 и libuv — ровно один. Еще есть пул потоков для асинхронного выполнения блокирующих системных вызовов.

Ровно один плюс еще пул это не ровно один.

Так сколько потоков?

С нодой имею дело только ради поиграться и webpack.
Ответил на всё, кроме 4-го. Вообще самые основы.

>Если стек будет полон, процесс окажется нагружен какой-то работой.

Простите, что?
Наверное имелось в виду не «полон», а «заполнен».

Что значит "только один стек вызовов на процесс"? Во-первых, многопоточность — у каждого потока свой стек вызовов и свой event loop. Во-вторых, генераторы и async-функции, которые сохраняют свой call stack между вызовами.

У меня когнитивный диссонанс. Node, и «понять как работает стек» — это как-то вообще какие-то диаметрально противоположные вселенные. Нет?
Ну вообще полезно знать как работает то, чем пользуетесь :)

Как минимум о цикле событий, об изолированности модулей и о том, что не нужно в однопоточном приложении блокировать поток.
Блокировка потока точно не специфика ноды, как и работа стека.
Там выше человек утверждает, что в синхронном чтении файлов нет ничего плохого.
Вы точно увсерены, что «блокировка потока — не специфика ноды»? :)

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

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

Не знаю что там было 20 лет назад. Я тогда думал как купить мороженное.

А вот в наше время при работе с Node.js желательно знать такие вещи как «блокировка потока». Хотя бы про синхронные чтения файлов или запросы к БД.

Ну, может это я так придираюсь и хочу слишком многого от сегодняшних пограмистов.

В наше время желательно знать такие вещи как "блокировка потока" при программировании на любом языке. JS ничем особым не выделяется.

Практически не использую Ноду, но смог правильно ответить на 7 вопросов из 10.

У вас точно был полный зал разработчиков Node?
посмотрите выше на спорящих с автором и удивление пропадёт.
Ну ладно, там человек просто считал, что асинхронность === многопоточность. (Ну как «просто» — конечно странно работать с Node и не знать этого, ну да ладно).

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

Сейчас и браузерный JS так же работает. Webpack, по моему, уже в каждой подворотне и уж хотя бы раз, но человек видел итоговый JS, который он создает.
У меня, например, похожая ситуация.
Я Ноду не использую вообще. Немного изучал её раньше.
Ответил на 9 из 10 вопросов.
Так что кажется, что автор всё-таки приувеличивает количество не ответивших.
Или просто многие не стали поднимать руки зная ответ на вопрос.
Всё верно же! Множества людей пишущих на ноде и не пишущих на ней — банально не пересекаются :))
за информацию про IIFE модулей отдельное спасибо, оказалось всё просто

Не будем переходить на личности, но есть у меня подозрение, что если уровень доклада был сравним со статьёй, люди, знающие ноду, просто тихонько слились поискать доклад поинтереснее. Потому что статья ну вообще ни о чём. От того, что я узнал, что библитоека, реализующая в ноде event loop, называется libuv, мне ни тепло ни холодно. Вряд ли те, кому это как раз не помешало бы, поймут, узнав название, что такое event loop вообще, и куда его прикладывать чтоб проняло.
Про стек вызовов вообще какая-то невнятная муть написана, и непонимающим понимания она точно не прибавит, да и я что-то в собственных знаниях засомневался, уж больно мутно.

Интересная статья. Согласен с тем, что информации о ноде и ECMAScript/js очень много, поэтому люди просто тонут в этой информации *И* не находят основные вещи.
Где почитать концентрированную инфу о Node.js (без воды), чтобы там были ответы на эти вопросы?
Sign up to leave a comment.