Как правильно обращаться с асинхронностью в узле узла? - PullRequest
0 голосов
/ 01 октября 2011

Я совершенно новый для всего стека - javascript, node.js, coffeescript, nodeunit. Думаешь, я должен сделать это шаг за шагом? Вы, вероятно, правы, но я все равно не собираюсь этого делать.

Вот тестовый файл:

testCase = require('nodeunit').testCase

Server = require('./web').WebServer
Client = require('../lib/client').Client
Request = require('../lib/request').Request

OPTIONS = {host: 'localhost', port: 8080, path: '/', method: 'GET'}
SERVER = new Server OPTIONS.port
CLIENT = new Client
REQUEST = new Request OPTIONS
SERVER.start() # asynchronous!

module.exports = testCase
  setUp: (callback) ->
    callback()

  tearDown: (callback) ->
    callback()

  testResponseBodyIsCorrect: (test) ->
    test.expect 1
    process.nextTick ->
      CLIENT.transmit REQUEST #asynchronous!
      process.nextTick ->
        test.equal REQUEST.body, /Ooga/
        test.done()

Внутренне это просто оболочка для библиотеки http. Я использую узел 0.4.11. Это на самом деле не работает. Здесь есть два асинхронных вызова. Если я делаю это вручную в REPL для кофе, он работает, но узел узла работает намного быстрее, чем я, поэтому я сталкиваюсь с чем-то, что, если быть умным, я назову условием гонки. усмешка

Вот реализация 'forward': Http = требуется 'http'

exports.Client = class Client

  transmit: (request, callback = null) ->
    req = Http.request request.options, (res) ->
      res.setEncoding 'utf8'
      res.on 'data', (chunk) ->
        request.appendToResponseBody chunk
    req.end()

    console.log "Request sent!"

Мне нужно убедиться, что сервер привязан к порту, прежде чем запустить тест, и мне нужно убедиться, что ".transmit" завершил свои внутренние обратные вызовы, чтобы получить ответ, прежде чем я сделаю утверждение.

Каков чистый способ (или, по крайней мере, способ, который работает), чтобы сделать это?

1 Ответ

1 голос
/ 01 октября 2011

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

CLIENT.transmit ЗАПРОС process.nextTick -> ...

сделать

CLIENT.transmit REQUEST, (ответ) -> ...

(я предполагаю, что ваш CLIENT.transmit метод реализован таким образом, что он вызывает обратный вызов с полученным ответом - должен!)

Теперь, если вы пытаетесь одновременно протестировать клиент и сервер, вам следует использовать EventEmitter - я думаю, вы обнаружите, что ваш объект SERVER уже один, так как он наследует от типа http.Server узла. Поскольку http.Server объекты запускают событие request всякий раз, когда они получают запрос, вы можете делать такие вещи, как

SERVER.on 'request', (request) ->
  test.equals REQUEST.body, request.body

Довольно мило, верно? Асинхронность в стиле узла может быть сногсшибательной, но она дает вам удивительный набор возможностей.

...