Just to add a slightly shorter/arguably cleaner example for using the 
*async* module (if using waterfall, embrace that it's a waterfall!):

CDN.use(config.CDN.baseUrl, function(req, res, next) {
  var req_path = config.base+"/cdn"+req.url;
  async.waterfall([
    fs.lstat.bind(fs, req_path),
    function (stats, cb) {
      if (!stats.isSymbolicLink()) {
        return next();
      }
      cb(req_path);
    },
    fs.readlink,
    fs.readFile,
    function (data) {
      res.writeHead(200,{"Content-type":"text/html"});
      res.end(data);
    }
  ], next);
});


I've spent most of my time in Node writing high performance network layers 
and related things and less time writing the "business logic", so I prefer 
to write as close to the metal as possible, mostly so that I can look at 
code and know at a glance what the async steps are, and I find this rather 
readable.  Additionally, when really trying to get the most performance, 
things like closures or .bind calls (which allocate memory that won't get 
collected in the early/quick generational garbage collection if your async 
tasks take any significant amount of time) are to be avoided (irrelevant in 
this case, since file I/O is going to have so much more overhead than 
anything you could possibly change syntactically here).

However, there's a pretty big barrier to entry here - getting a new 
(perhaps not as awesome as all of you) person to a team asynchronous 
Javascript code, they can be incredibly baffled (though, usually, only when 
it gets to things like loops, not for simple chained stuff like the 
examples in this thread).  I suspect that if I had them use streamline 
instead, I would have spent a lots less time unravelling the first async 
code they wrote (admittedly, once they've done an async loop themselves a 
couple times to understand it, and then learn how to write it much more 
succinctly with the *async* module, they're generally fine after that).

Also, assuming we want what the original posted requested (middleware that 
just handles symlinks, leaving regular files alone to the rest of his 
stack), the streamline version, I think, looks like this:
CDN.use(config.CDN.baseUrl, function(req, res, next, _) {
  var path = config.base + "/cdn" + req.url;
  if (!fs.lstat(path, _).isSymbolicLink()) {
    return next();
  }
  path = fs.readlink(path, _); 
  res.writeHead(200, { "Content-type" : "text/html" }); 
  res.end( fs.readFile(path, _));
});



Though, as someone very familiar with the pitfalls of Javascript, and very 
unfamiliar with streamline, I'd have to look at the generated code to 
assure myself that's actually doing what I think I want it to, as I could 
imagine many ways in which that code could be converted to raw asynchronous 
code incorrectly (I'll assume for now it's smart enough and does it right ; 
).

  Jimb Esser

On Tuesday, September 23, 2014 4:29:46 AM UTC-7, Alexey Petrushin wrote:
>
> Ha-ha, very good example, compare this async version it with the sync 
> version below, and tell me that there's no problem with 
> callbacks """if you know how to deal with it""" :D
>
> Not saying that in even such a simple code it's extremely
> easy to make small errors like missing `else` statements etc.
>
> Also it doesn't preserve the call stack - so when you see error in console
> you would have no context and no idea what happened...
> And it still doesn't catch the sync errors...
> And some of callbacks can be fired twice...
> And with streams there are lots of events fired and should be properly 
> handled...
>
> And still many insist that it is "not a problem".
>
>     CDN.use(config.CDN.baseUrl, function(req, res, next) {
>         if(err) return next(err);
>         async.waterfall([
>             function (cb) {
>                 fs.lstat(config.base+"/cdn"+req.url, cb);
>             },
>             function (stats, cb) {
>                 if(stats.isSymbolicLink()) {
>                     async.waterfall([
>                         function (cb) {
>                             fs.readlink(config.base+"/cdn"+req.url, cb);
>                         },
>                         function (linkstr, cb) {
>                             log.info("Redirecting request \""+req.url+"\" 
> to \""+linkstr);
>                             fs.readFile(linkstr, cb);
>                         },
>                     ], cb);
>                 }
>             }
>         ], function (err, data) {
>             if (err) return next(err);
>             res.writeHead(200,{"Content-type":"text/html"});
>             res.end(data);
>         });
>     });
>     
> Sync version.
>
>     CDN.use(config.CDN.baseUrl, function(req, res, next) {
>       var stats = fs.lstat(config.base+"/cdn"+req.url)
>       if(stats.isSymbolicLink()) {
>         var linkstr = fs.readlink(config.base+"/cdn"+req.url);
>         log.info("Redirecting request \""+req.url+"\" to \""+linkstr);
>         var data = fs.readFile(linkstr);
>         res.writeHead(200,{"Content-type":"text/html"});
>         res.end(data);
>       }
>     });
>
> On Monday, 22 September 2014 05:18:40 UTC+4, Matt Sergeant wrote:
>>
>>
>> On Sat, Sep 20, 2014 at 9:17 AM, Bruno Jouhier <bjou...@gmail.com> wrote:
>>
>>> How do you implement it with async?
>>
>>
>> This is a good question, so here's an example translation (not the only 
>> way to do it):
>>
>>
>>     CDN.use(config.CDN.baseUrl, function(req, res, next) {
>>         if(err) return next(err);
>>         async.waterfall([
>>             function (cb) {
>>                 fs.lstat(config.base+"/cdn"+req.url, cb);
>>             },
>>             function (stats, cb) {
>>                 if(stats.isSymbolicLink()) {
>>                     async.waterfall([
>>                         function (cb) {
>>                             fs.readlink(config.base+"/cdn"+req.url, cb);
>>                         },
>>                         function (linkstr, cb) {
>>                             log.info("Redirecting request 
>> \""+req.url+"\" to \""+linkstr);
>>                             fs.readFile(linkstr, cb);
>>                         },
>>                     ], cb);
>>                 }
>>             }
>>         ], function (err, data) {
>>             if (err) return next(err);
>>             res.writeHead(200,{"Content-type":"text/html"});
>>             res.end(data);
>>         });
>>     });
>>
>> It's more code, but it improves the error checking. If it didn't have 
>> that "if" statement in there it would be a lot simpler - async code doesn't 
>> deal well with "if" statements I've found (there's no way to short-circuit).
>>
>> Matt.
>>
>

-- 
Job board: http://jobs.nodejs.org/
New group rules: 
https://gist.github.com/othiym23/9886289#file-moderation-policy-md
Old group rules: 
https://github.com/joyent/node/wiki/Mailing-List-Posting-Guidelines
--- 
You received this message because you are subscribed to the Google Groups 
"nodejs" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to nodejs+unsubscr...@googlegroups.com.
To post to this group, send email to nodejs@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/nodejs/bdfcf7e8-6316-4f07-a714-9407402df65b%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to