Trace at c (repl:3:9) at b (repl:3:1) at a (repl:3:1) at repl:1:1// <-- 这个指针下面的东西都是Nodejs的内部实现,无视就好 at realRunInThisContextScript (vm.js:22:35) at sigintHandlersWrap (vm.js:98:12) at ContextifyScript.Script.runInThisContext (vm.js:24:12) at REPLServer.defaultEval (repl.js:313:29) at bound (domain.js:280:14) at REPLServer.runBound [aseval] (domain.js:293:12)
functionrunWithoutThrowing(func) { try { func(); } catch (e) { console.log('There was an error, but I will not throw it.'); console.log('The error\'s message was: ' + e.message) } }
functionfuncThatThrowsError() { thrownewTypeError('I am a TypeError.'); }
functionrunWithoutThrowing(func) { try { func(); } catch (e) { console.log('There was an error, but I will not throw it.'); console.log('The error\'s message was: ' + e.message) } }
functionfuncThatThrowsString() { throw'I am a String.'; }
newPromise(function(resolve, reject) { reject(newError('The promise was rejected.')); }).then(function() { console.log('I am an error.'); }).catch(function(err) { if (err instanceofError) { console.log('The promise was rejected with an error.'); console.log('Error Message:' + err.message); } })
// 这将会在控制台中打印出如下信息: // at b (repl:3:7) <-- 因为它在B内被调用,所以B是堆栈中的最后一个条目 // at a (repl:2:1) // at repl:1:1 <-- 下面是 node 的内部实现 // at realRunInThisContextScript (vm.js:22:35) // at sigintHandlersWrap (vm.js:98:12) // at ContextifyScript.Script.runInThisContext (vm.js:24:12) // at REPLServer.defaultEval (repl.js:313:29) // at bound (domain.js:280:14) // at REPLServer.runBound [as eval] (domain.js:293:12) // at REPLServer.onLine (repl.js:513:10)
正如你在上述例子中看到的,我们首先调用了 a (被压入了栈内)然后在 a 内调用了 b (被 push 在 a 上面)。然后,在 b 内,我们捕获到了当前的堆栈信息,并且存入了 myObj。 这就是为什么我们在控制台中只获得了 a 和 b。
// 这将会在控制台中打印出如下信息: // at a (repl:2:1) <-- 如你所见在这里我们只能获得 `b` 之前的被调用的栈帧 // at repl:1:1 <-- 下面是 node 的内部实现 // at realRunInThisContextScript (vm.js:22:35) // at sigintHandlersWrap (vm.js:98:12) // at ContextifyScript.Script.runInThisContext (vm.js:24:12) // at REPLServer.defaultEval (repl.js:313:29) // at bound (domain.js:280:14) // at REPLServer.runBound [as eval] (domain.js:293:12) // at REPLServer.onLine (repl.js:513:10) // at emitOne (events.js:101:20)
当我们传递 b 给Error.captureStackTrace 函数时,它隐藏了 b 本身以及在它之上的所有栈帧。这就是为什么我们在堆栈追踪中只看到了a。
functionassertLength (n, msg) { if (msg) flag(this, 'message', msg); var obj = flag(this, 'object') , ssfi = flag(this, 'ssfi');
// 注意这一行 newAssertion(obj, msg, ssfi, true).to.have.property('length'); var len = obj.length;
// 这一行也同样相关 this.assert( len == n , 'expected #{this} to have a length of #{exp} but got #{act}' , 'expected #{this} to not have a length of #{act}' , n , len ); }
functionAssertion (obj, msg, ssfi, lockSsfi) { // This is the line that matters to us flag(this, 'ssfi', ssfi || Assertion); flag(this, 'lockSsfi', lockSsfi); flag(this, 'object', obj); flag(this, 'message', msg);
while (queue.waitForMessage()) { queue.processNextMessage(); }
queue.waitForMessage 同步的等待消息到来,如果当前还没有的话。
从运行到完成
每一条消息都在另一条消息被处理前完成。这提供了一些不错的特性在对你的程序追责时,它记录了函数运行的状态,函数执行时总会在其他代码捷足先登前完全的被执行,(并可以修改函数操作时的数据)。与 C 不同的是,比如(以下为 C 的情况), 如果一个方法在一个线程上跑的时候,它可以在任何时候被中断,并且在另一个线程上跑一些其它的代码。
/* Drop this mixin into a component that wastes time according to Perf.getWastedTime() to find out what state/props should be preserved. Once it says "Update avoidable!" for {state, props}, you should be able to drop in React.addons.PureRenderMixin React.createClass { mixins: [WhyDidYouUpdateMixin] } */ functionisRequiredUpdateObject(o) { returnArray.isArray(o) || (o && o.constructor === Object.prototype.constructor); }
你会发现当你把你的组件拆分成两类时,它们会变得更加易于复用和理解。我称呼他们为容器组件和展示组件,不过我同样也听到如下几种说法,胖组件(Fat)和瘦(Shinny)组件,聪明组件(Smart)和呆(Dumb)组件,多状态(Statefull)组件和纯(Pure)组件,放映和组件(Screens and Components)。它们不尽相同,但核心的思想却非常接近。