Чому я можу виконувати код після “res.send”?


80

Мені цікаво, в чому полягає механіка поведінки наступного коду:

res.send(200, { data: 'test data' });
console.log('still here...');

Я розумію, що функція res.sendне повертає , але перериває з'єднання / завершує запит . Це може пояснити, чому я все ще можу виконувати код після res.sendкоманди (я переглядав експрес-джерело, і це, здається, не є асинхронною функцією).

Чи є щось інше у грі, чого мені може не вистачати?


вибачте, я неправильно прочитав ваш допис і не був впевнений, у чому проблема з вашим кодом, оскільки він цілком законний. коли ви називаєте sendце, просто передає дані з http-з'єднання, і ваш код продовжується. Ви можете просто використовувати, returnякщо хочете припинити код, або просто не писати нічого іншого. вибачте за неправильне тлумачення.
Тіммерц

Відповіді:


127

Звичайно, endзакінчується відповідь HTTP, але це не робить нічого особливого для вашого коду.

Ви можете продовжувати робити інші речі навіть після того, як закінчите відповідь.

Однак те, що ви не можете зробити, це зробити щось корисне res. Оскільки відповідь закінчена, ви не можете записати до неї більше даних.

res.send(...);
res.write('more stuff'); // throws an error since res is now closed

Ця поведінка на відміну від інших традиційних фреймворків (PHP, ASP тощо), які виділяють потік для запиту HTTP і завершують потік, коли відповідь закінчується. Якщо ви викликаєте еквівалентну функцію, подібну до ASP Response.End, потік завершується, і ваш код перестає працювати. У вузлі немає потоку для зупинки. reqі resбільше не запускатиме жодних подій, але код у ваших зворотних викликах може продовжувати працювати (до тих пір, поки він не намагатиметься викликати методи, для resяких потрібна дійсна відповідь)


8
ця відповідь була дуже корисною і переконала мене залишити nodejs з ідеологічних міркувань.
jkatzer

33
Ідеологія @jkatzer слабка. перемагає прагматизм.
Анатолій Г

8
Звичайно, спробуйте пам’ятати, що Node - це просто середовище виконання, якщо ви використовуєте expressjs, це ваш веб-сервер. Те, що ви говорите, схоже на питання, чому Apache продовжує працювати після того, як php повертає відповідь. Ви можете вибрати використовувати цю додаткову ємність, можливо, ви хочете зареєструвати стан відповіді після її надсилання, або виконати деякі інші функції програми, що залежить від вас. Однак з великою владою приходить велика відповідальність ...
самазі

11
@jkatzer - Ваше твердження є абсолютно безглуздим та демонструє токсичну психіку.
Dembinski

1
@AnatolyG Я читав ваш коментар щонайменше 5 разів, читаючи цей розділ коментарів, і щоразу читав його плагіат і сміявся над ним, тепер над собою. Лол.
Lalit Fauzdar

44

Редагувати: Я більше не роблю те, що пояснено нижче, оскільки ви не повинні повертати значення, коли в цьому немає потреби. Це робить ваш код менш читабельним і виглядає хакерським. Натомість я пропоную відокремити оператор return від res.send(). @slavafomin це добре пояснив у коментарях.

Простий спосіб зупинити виконання функції та одночасно надіслати відповідь - це зробити

return res.send('500', 'Error message here');

Це дозволяє використовувати короткі ifоператори для обробки таких помилок, як:

if (err) {
    return res.send('500', 'Error message here');
}

Точний повернення з res.sendфункції є об'єкт , який , здається, містить все стан з'єднання після того, як ви закінчили його (запит, статус, заголовки і т.д.), але це повинно бути неважливо , так як ви не будете робити нічого з ним.


2
Це чудовий момент, але технічно не відповідь. оскільки питання більше стосується чому, а не як. Тим не менше, великий внесок, отже, і "за".
Nepoxx

3
Так, на той момент я не міг коментувати, тому мені довелося розмістити відповідь.
Маркос Перейра

4
Я б не рекомендував використовувати цю техніку. Це робить код коротшим, але також робить його менш значущим і розмитим, оскільки використовує неправильну семантику. Якщо ви не використовуєте значення з функції, тоді вам не слід його повертати. Також він може зламати набраний JavaScript (наприклад, TypeScript) та інструменти, що використовують статичний аналіз коду. Іншими словами: це виглядає хакерською та непрофесійною.
Слава Фомін II

1
@SlavaFominII Це може бути так: res.send('500', 'Error message here');return;внутрішнє ifтвердження.
Алі Шерафат,

@SlavaFominll Я думаю, що цей метод настільки поширений, що його вже не можна назвати хакерським. Що стосується статичних аналізаторів - оскільки експрес-розробники є тими, хто обробляє повернення від цієї функції, я майже впевнений, що тут не надто турбуватися. Ви стикалися з конкретною проблемою?
Охад Коен,

0

Можливе рішення - за допомогою цієї бібліотеки: on-finished

var destroy = require('destroy')
var fs = require('fs')
var http = require('http')
var onFinished = require('on-finished')

http.createServer(function onRequest (req, res) {
  var stream = fs.createReadStream('package.json')
  stream.pipe(res)
  onFinished(res, () => {
    destroy(stream)
  })
})

Працює і з Express , наприклад:

const express = require('express');
const app = express();

app.get('/video', (req, res) => {
 const ffmpeg = spawn(ffmpegPath, argsArray);
 ffmpeg.stdout.pipe(res);
 onFinished(res, () => {
   ffmpeg.kill();
 });
});
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.