Question

I am newer for IronRouter, why readFile callback executed the response are send to client.

Router.map(
  ()->
    this.route 'readFile',
      path: '/readFile'
      where: 'server'
      method: 'GET'
      action: ()->
        self = this
        fs.readFile '/tmp/a.txt', (err, data)->
          if err
            throw err
          console.log(data.toString())
          self.response.writeHead(200, {'Content-Type': 'text/plain'})
          self.response.end(data)
        console.log('response ...')

)

http.js:733
  W2049-12:04:26.781(8)? (STDERR)     throw new Error('Can\'t render headers after they are sent to the client.'
  W2049-12:04:26.781(8)? (STDERR)           ^
  W2049-12:04:26.782(8)? (STDERR) Error: Can't render headers after they are sent to the client.

But, I use express , like this is work well.

exports.index = function(req, res){
  fs.readFile('/tmp/a.txt', function (err, data) {
    if (err) throw err;
    console.log(data.toString());
    res.send(200, data.toString());
  });
  console.log('response ...');
};

thanks @ChristianF @Tarang Use Meteor._wrapAsync or Future all work well . when I use self define function replace fs.readFile. It take throw ex . I Doubt My defined function has error. As follows:

@getAccounts = (callback) ->
 query = "SELECT Id, Name, AccountNumber FROM Account"
 queryBySoql(query, (err, result)->
   if err
     return console.error(err)
   return callback(result)
)

I invoked link this:

# using Meteor
#data = Meteor._wrapAsync(getAccounts)()


#using Future
waiter = Future.wrap(getAccounts)()
data = waiter.wait()
this.response.writeHead 200, {'Content-Type': 'text/plain'}
this.response.end JSON.stringify(data)

thanks all.

Was it helpful?

Solution

Just today I struggled with this very issue. The answer, it seems to me, is that meteor (or at least the iron router) doesn't handle async calls the way you'd expect. The solution is to wrap the async call into a fiber, which is the mechanism meteor uses to keep the programming synchronous.

In your case try this (sorry, I don't know coffeescript very well):

var Future = Npm.require('fibers/future');
...
var waiter = Future.wrap(fs.readFile);
var data = waiter('/tmp/a.txt').wait();
response.writeHead(200, {'Content-Type': 'text/plain'})
response.end(data)

EDIT Addressing the addition to the question.

Functions wrapped in a future need to have a callback as their last argument that has the (err, result) signature. Try this:

@getAccounts = (callback) ->
 query = "SELECT Id, Name, AccountNumber FROM Account"
 queryBySoql(query, (err, result)->
   if err
     return console.error(err)
   return callback(err, result)
)

OTHER TIPS

You could wrap up your read file request's callback into the same fiber. It will not block other requests & comes out quite clean.

readFile = Meteor_wrapAsync(fs.readFile.bind(fs))
data = readFile("/tmp/a.txt")

console.log data
@response.writeHead(200, {'Content-Type': 'text/plain'})
@response.end data
return
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top