
try { process.nextTick(function() { throw new Error('Catch Me If You Can'); }); } catch (e) { console.log('Exception caught:', e); }  /** *  Block        . */ function Block(errback) { this._parent=Block.current; this._errback=errback; } Block.current=null; /** *  ,   ,     , *           guard(). *     ,   . * * Example: stream.on('end', Block.guard(function() { ... })); */ Block.guard=function(f) { if (this.current) return this.current.guard(f); else return f; }; /** *      .  -     (" try"). *  -    ('catch'). */ Block.begin=function(block, rescue) { var ec=new Block(rescue); return ec.trap(block); }; /** *   function(err),        , *       (  ,    ). *      err  true. * * Example: request.on('error', Block.errorHandler()) */ Block.errorHandler=function() { // Capture the now current Block for later var current=this.current; return function(err) { if (!err) return; if (current) return current.raise(err); else throw err; }; }; /** *    .     error handler,     . *   raise(...)     .    , *        throw. *  ,   error handler'  , *     error handler'. */ Block.prototype.raise=function(err) { if (this._errback) { try { this._errback(err); } catch (nestedE) { if (this._parent) this._parent.raise(nestedE); else throw nestedE; } } else { if (this._parent) this._parent.raise(err); else throw(err); } }; /** *   callback    . *       raise()  . *  return value   undefined   . */ Block.prototype.trap=function(callback) { var origCurrent=Block.current; Block.current=this; try { var ret=callback(); Block.current=origCurrent; return ret; } catch (e) { Block.current=origCurrent; this.raise(e); } }; /** *  ,        . *     trap(),       . */ Block.prototype.guard=function(f) { if (f.__guarded__) return f; var self=this; var wrapped=function() { var origCurrent=Block.current; Block.current=self; try { var ret=f.apply(this, arguments); Block.current=origCurrent; return ret; } catch (e) { Block.current=origCurrent; self.raise(e); } }; wrapped.__guarded__=true; return wrapped; };  Block.begin(function() { process.nextTick(Block.guard(function() { throw new Error; })); }, function(err) { console.log('Exception caught:', err); }); Now the exception is processed, and we can not drop the server. This also works with setTimeout, EventEmitter, callbacks for requests to the database, and anything else.function(err) { ; next(err); } function(err) { ; next(err); } function(err) { ; next(err); } . You can also use inline functions in Block.begin calls for greater visual similarity to try / catch, but I prefer to use named callbacks to increase readability. function handleUserAgent(req, res, next) { return Block.begin(process, next); function process() { jsonifyRequest(req, withRequest); //  ,   jsonifyRequest , //    Block.guard() } function withRequest(requestObj) { var r=validators.UserAgentRecord(requestObj, {fix:true}); if (!r.valid) { res.writeHead(400); return res.end('Invalid request object: ' + r.reason); } var uar=r.object; if (uar.token) { // Verify //return handler.verifyUserAgent(uar); throw new Error('verifyUserAgent not yet implemented'); } else { // Create uar.token=null; uar.type='auth'; // TODO: Maybe support unauth in the future? handler.createUserAgent(uar, Block.guard(withUserAgent)); } } function withUserAgent(userAgent) { var r=validators.UserAgentRecord(userAgent, {fix:true}); return respondJson(r.object, res); } }  request: function(options, callback) { var req=http.request(options, function(res) { var text=''; res.setEncoding('utf8'); res.on('data', function(chunk) { text+=chunk; }); res.on('end', Block.guard(function() { callback(new CouchResponse(res, text)); })); res.on('error', Block.errorHandler()); }); req.on('error', Block.errorHandler()); req.end(); } try{try{}catch{}}catch{} ). This is useful in code for frameworks that should do some work within a block created by someone else's code.Source: https://habr.com/ru/post/147233/
All Articles