ÓÐʱºòÈËÃDz¢²»¹Ø×¢ÕâЩϸ½Ú£¬µ«Õâ·½ÃæµÄ֪ʶ¿Ï¶¨ÓÐÓã¬ÓÈÆäÊǵ±ÄãÕýÔÚ±àдÓë²âÊÔ»òerrorsÏà¹ØµÄ¿â¡£ÀýÈçÕâ¸öÐÇÆÚÎÒÃǵÄchaiÖгöÏÖÁËÒ»¸öÁîÈ˾ªÌ¾µÄPull
Request£¬Ëü´ó´ó¸Ä½øÁËÎÒÃÇ´¦Àí¶ÑÕ»¸ú×ٵķ½Ê½£¬²¢ÔÚÓû§¶ÏÑÔʧ°ÜʱÌṩÁ˸ü¶àµÄÐÅÏ¢¡£
²Ù×÷¶ÑÕ»¼Ç¼¿ÉÒÔÈÃÄãÇåÀíÎÞÓÃÊý¾Ý£¬²¢¼¯Öо«Á¦´¦ÀíÖØÒªÊÂÏî¡£´ËÍ⣬µ±ÄãÕæÕýŪÇå³þError¼°ÆäÊôÐÔ£¬Ä㽫»á¸üÓÐÐÅÐĵØÀûÓÃËü¡£
±¾ÎÄ¿ªÍ·²¿·Ö»òÐíÌ«¹ýÓÚ¼òµ¥£¬µ«µ±Ä㿪ʼ´¦Àí¶ÑÕ»¼Ç¼ʱ£¬Ëü½«±äµÃÉÔ΢ÓÐЩ¸´ÔÓ£¬ËùÒÔÇëÈ·±£ÄãÔÚ¿ªÊ¼Õâ¸öÄDz¿·ÖÕ½Ú֮ǰÒѾ³ä·ÖÀí½âÇ°ÃæµÄÄÚÈÝ¡£
¶ÑÕ»µ÷ÓÃÈçºÎ¹¤×÷
ÔÚ̸ÂÛerrors֮ǰÎÒÃDZØÐëÃ÷°×¶ÑÕ»µ÷ÓÃÈçºÎ¹¤×÷¡£Ëü·Ç³£¼òµ¥£¬µ«¶ÔÓÚÎÒÃǽ«ÒªÉîÈëµÄÄÚÈݶøÑÔÈ´ÊÇÖÁ¹ØÖØÒªµÄ¡£Èç¹ûÄãÒѾ֪µÀÕⲿ·ÖÄÚÈÝ£¬ÇëËæÊ±Ìø¹ý±¾½Ú¡£
ÿµ±º¯Êý±»µ÷Óã¬Ëü¶¼»á±»ÍƵ½¶ÑÕ»µÄ¶¥²¿¡£º¯ÊýÖ´ÐÐÍê±Ï£¬±ã»á´Ó¶ÑÕ»¶¥²¿ÒƳý¡£
ÕâÖÖÊý¾Ý½á¹¹µÄÓÐȤ֮´¦ÔÚÓÚ×îºóÒ»¸öÈëÕ»µÄ½«»áµÚÒ»¸ö´Ó¶ÑÕ»ÖÐÒÆ³ý£¬ÕâÒ²¾ÍÊÇÎÒÃÇËùÊìϤµÄLIFO(ºó½ø£¬Ïȳö)ÌØÐÔ¡£
ÕâÒ²¾ÍÊÇ˵ÎÒÃÇÔÚº¯ÊýxÖе÷Óú¯Êýy,ÄÇô¶ÔÓ¦µÄ¶ÑÕ»ÖеÄ˳ÐòΪx y¡£
¼ÙÉèÄãÓÐÏÂÃæÕâÑùµÄ´úÂ룺
function c() { console.log('c');}
function b() {
console.log('b');
c();
}
function a() {
console.log('a');
b();
}
a(); |
ÔÚÉÏÃæÕâÀïÀý×ÓÖУ¬µ±Ö´ÐÐaº¯Êýʱ£¬a±ã»áÌí¼Óµ½¶ÑÕ»µÄ¶¥²¿£¬È»ºóµ±bº¯ÊýÔÚaº¯ÊýÖб»µ÷Óã¬bÒ²»á±»Ìí¼Óµ½¶ÑÕ»µÄ¶¥²¿£¬ÒÀ´ÎÀàÍÆ£¬ÔÚbÖе÷ÓÃcÒ²»á·¢ÉúͬÑùµÄÊÂÇé¡£
µ±cÖ´ÐÐʱ£¬¶ÑÕ»Öеĺ¯ÊýµÄ˳ÐòΪa b c
cÖ´ÐÐÍê±Ïºó±ã»á´ÓÕ»¶¥ÒƳý£¬Õâʱ¿ØÖÆÁ÷ÖØÐ»ص½ÁËbÖУ¬bÖ´ÐÐÍê±ÏͬÑùÒ²»á´ÓÕ»¶¥ÒƳý£¬×îºó¿ØÖÆÁ÷Óֻص½ÁËaÖУ¬×îºóaÖ´ÐÐÍê±Ï£¬aÒ²´Ó¶ÑÕ»ÖÐÒÆ³ý¡£
ÎÒÃÇ¿ÉÒÔÀûÓÃconsole.trace()À´¸üºÃµÄÑÝʾÕâÖÖÐÐΪ£¬Ëü»áÔÚ¿ØÖÆÌ¨´òÓ¡³öµ±Ç°¶ÑÕ»ÖеļǼ¡£´ËÍ⣬ͨ³£¶øÑÔÄãÓ¦¸Ã´ÓÉϵ½Ï¶ÁÈ¡¶ÑÕ»¼Ç¼¡£ÏëÏëÏÂÃæµÄÿһÐдúÂë¶¼ÊÇÔÚÄĵ÷Óõġ£
function c() { console.log('c'); console.trace(); }
function b() {
console.log('b');
c();
}
function a() {
console.log('a');
b();
}
a(); |
ÔÚNode REPL·þÎñÆ÷ÉÏÔËÐÐÉÏÊö´úÂë»áµÃµ½ÈçϽá¹û£º
Trace at c (repl:3:9) at b (repl:3:1) at a (repl:3:1) at repl:1:1 // <-- For now feel free to ignore anything below this point, these are Node's internals 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) |
ÈçÄãËù¼û£¬µ±ÎÒÃÇÔÚcÖдòÓ¡¶ÑÕ»£¬¶ÑÕ»ÖеļǼΪa,b,c¡£
Èç¹ûÎÒÃÇÏÖÔÚÔÚbÖв¢ÇÒÔÚcÖ´ÐÐÍêÖ®ºó´òÓ¡¶ÑÕ»£¬ÎÒÃǽ«»á·¢ÏÖcÒѾ´Ó¶ÑÕ»µÄ¶¥²¿ÒƳý£¬Ö»Ê£ÏÂÁËaºÍb¡£
function c() { console.log('c'); }
function b() {
console.log('b');
c();
console.trace();
}
function a() {
console.log('a');
b();
}
a(); |
ÕýÈçÄã¿´µ½µÄÄÇÑù£¬¶ÑÕ»ÖÐÒѾûÓÐc£¬ÒòΪËüÒѾÍê³ÉÔËÐУ¬ÒѾ±»µ¯³öÈ¥ÁË¡£
Trace at b (repl:4:9) at a (repl:3:1) at repl:1:1 // <-- For now feel free to ignore anything below this point, these are Node's internals 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) |
×ܽ᣺µ÷Ó÷½·¨£¬·½·¨±ã»áÌí¼Óµ½¶ÑÕ»¶¥²¿£¬Ö´ÐÐÍê±ÏÖ®ºó£¬Ëü¾Í»á´Ó¶ÑÕ»Öе¯³ö¡£
Error¶ÔÏó ºÍ Error´¦Àí
µ±³ÌÐò·¢Éú´íÎóʱ£¬Í¨³£¶¼»áÅ׳öÒ»¸öError¶ÔÏó¡£Error¶ÔÏóÒ²¿ÉÒÔ×÷Ϊһ¸öÔÐÍ£¬Óû§¿ÉÒÔÀ©Õ¹Ëü²¢´´½¨×Ô¶¨Òå´íÎó¡£
Error.prototype¶ÔÏóͨ³£ÓÐÒÔÏÂÊôÐÔ£º
1.constructor- ʵÀýÔÐ͵Ĺ¹Ô캯Êý¡£
2.message - ´íÎóÐÅÏ¢
3.name - ´íÎóÃû³Æ
ÒÔÉ϶¼ÊDZê×¼ÊôÐÔ£¬£¨µ«£©ÓÐʱºòÿ¸ö»·¾³¶¼ÓÐÆäÌØ¶¨µÄÊôÐÔ£¬ÔÚÀýÈçNode£¬Firefox£¬Chorme£¬Edge£¬IE
10+£¬Opera ºÍ Safari 6+ ÖУ¬»¹ÓÐÒ»¸ö°üº¬´íÎó¶ÑÕ»¼Ç¼µÄstackÊôÐÔ¡£´íÎó¶ÑÕ»¼Ç¼°üº¬´Ó£¨¶ÑÕ»µ×²¿£©Ëü×Ô¼ºµÄ¹¹Ô캯Êýµ½£¨¶ÑÕ»¶¥²¿£©ËùÓеĶÑÕ»Ö¡¡£
Èç¹ûÏëÁ˽â¸ü¶à¹ØÓÚError¶ÔÏóµÄ¾ßÌåÊôÐÔ£¬ÎÒÇ¿ÁÒÍÆ¼öMDNÉϵÄÕâÆªÎÄÕ¡£
Å׳ö´íÎó±ØÐëʹÓÃthrow¹Ø¼ü×Ö£¬Äã±ØÐ뽫¿ÉÄÜÅ׳ö´íÎóµÄ´úÂë°ü¹üÔÚtry´úÂë¿éÄÚ²¢½ô¸ú×ÅÒ»¸öcatch´úÂë¿éÀ´²¶»ñÅ׳öµÄ´íÎó¡£
ÕýÈçJavaÖеĴíÎó´¦Àí,try/catch´úÂë¿éºó½ô¸ú×ÅÒ»¸öfinally´úÂë¿éÔÚJavaScriptÖÐÒ²ÊÇͬÑùÔÊÐíµÄ£¬ÎÞÂÛtry´úÂë¿éÄÚÊÇ·ñÅ׳öÒì³££¬finally´úÂë¿éÄڵĴúÂë¶¼»áÖ´ÐС£ÔÚÍê³É´¦ÀíÖ®ºó£¬×î¼Ñʵ¼ùÊÇÔÚfinally´úÂë¿éÖÐ×öһЩÇåÀíµÄÊÂÇ飬(ÒòΪ)ÎÞÂÛÄãµÄ²Ù×÷ÊÇ·ñÉúЧ£¬¶¼²»»áÓ°Ïìµ½ËüµÄÖ´ÐС£
(¼øÓÚ)ÉÏÃæËù̸µ½µÄËùÓÐÊÂÇé¶Ô´ó¶àÊýÈËÀ´½²¶¼ÊÇС²ËÒ»µú£¬ÄÇô¾ÍÈÃÎÒÃÇÀ´Ì¸Ò»Ð©²»ÎªÈËËùÖªµÄϸ½Ú¡£
try´úÂë¿éºóÃæ²»±Ø½ô¸ú×Åcatch,µ«(´ËÖÖÇé¿öÏÂ)Æäºó±ØÐë½ô¸ú×Åfinally¡£ÕâÒâζ×ÅÎÒÃÇ¿ÉÒÔʹÓÃÈýÖÖ²»Í¬ÐÎʽµÄtryÓï¾ä£º
TryÓï¾ä¿ÉÒÔÏñÏÂÃæÕâÑù»¥ÏàǶÌ×£º
try { try { throw new Error('Nested error.'); // The error thrown here will be caught by its own `catch` clause } catch (nestedErr) { console.log('Nested catch'); // This runs } } catch (err) { console.log('This will not run.'); } |
ÄãÉõÖÁ»¹¿ÉÒÔÔÚcatchºÍfinally´úÂë¿éÖÐǶÌ×tryÓï¾ä£º
try { throw new Error('First error'); } catch (err) { console.log('First catch running'); try { throw new Error('Second error'); } catch (nestedErr) { console.log('Second catch running.'); } } |
try { console.log('The try block is running...'); } finally { try { throw new Error('Error inside finally.'); } catch (err) { console.log('Caught an error inside the finally block.'); } } |
»¹ÓкÜÖØÒªµÄÒ»µãÖµµÃ×¢Ò⣬ÄǾÍÊÇÎÒÃÇÉõÖÁ¿ÉÒÔ´ó¿É²»±ØÅ׳öError¶ÔÏó¡£¾¡¹ÜÕâ¿´ÆðÀ´·Ç³£coolÇҷdz£×ÔÓÉ£¬µ«Êµ¼Ê²¢·ÇÈç´Ë£¬ÓÈÆäÊǶԿª·¢µÚÈý·½¿âµÄ¿ª·¢ÕßÀ´Ëµ£¬ÒòΪËûÃDZØÐë´¦ÀíÓû§(ʹÓÿâµÄ¿ª·¢Õß)µÄ´úÂë¡£ÓÉÓÚȱ·¦±ê×¼£¬ËûÃDz¢²»ÄܰѿØÓû§µÄÐÐΪ¡£Äã²»ÄÜÏàÐÅÓû§²¢¼òµ¥µÄÅ׳öÒ»¸öError¶ÔÏó£¬ÒòΪËûÃDz»Ò»¶¨»áÄÇô×ö¶øÊǽö½öÅ׳öÒ»¸ö×Ö·û´®»òÕßÊý×Ö(¹íÖªµÀÓû§»áÅ׳öʲô)¡£ÕâҲʹµÃ´¦Àí±ØÒªµÄ¶ÑÕ»¸ú×ÙºÍÆäËûÓÐÒâÒåµÄÔªÊý¾Ý±äµÃ¸ü¼ÓÀ§ÄÑ¡£
¼ÙÉèÓÐÒÔÏ´úÂ룺
function runWithoutThrowing(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) } }
function funcThatThrowsError() {
throw new TypeError('I am a TypeError.');
}
runWithoutThrowing(funcThatThrowsError); |
Èç¹ûÄãµÄÓû§ÏñÉÏÃæÕâÑù´«µÝÒ»¸öÅ׳öError¶ÔÏóµÄº¯Êý¸ørunWithoutThrowingº¯Êý(ÄǾÍлÌìлµØÁË)£¬È»¶ø×ÜÓÐЩÈË͵ÏëÀÁÖ±½ÓÅ׳öÒ»¸öString,ÄÇÄã¾ÍÂé·³ÁË£º
function runWithoutThrowing(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) } }
function funcThatThrowsString() {
throw 'I am a String.';
}
runWithoutThrowing(funcThatThrowsString); |
ÏÖÔÚµÚ¶þ¸öconsole.log»á´òÓ¡³ö the error¡¯s message is undefined.Õâô¿´À´Ò²Ã»¶à´óµÄÊÂ(ºó¹û)ѽ£¬µ«ÊÇÈç¹ûÄúÐèҪȷ±£Ä³Ð©ÊôÐÔ´æÔÚÓÚError¶ÔÏóÉÏ£¬»òÒÔÁíÒ»ÖÖ·½Ê½£¨ÀýÈçChaiµÄthrows¶ÏÑÔ
does)£©´¦ÀíError¶ÔÏóµÄÌØ¶¨ÊôÐÔ£¬ÄÇôÄã×öÐèÒª¸ü¶àµÄ¹¤×÷£¬ÒÔÈ·±£Ëü»áÕý³£¹¤×Ê¡£
´ËÍ⣬µ±Å׳öµÄÖµ²»ÊÇError¶ÔÏóʱ£¬ÄãÎÞ·¨·ÃÎÊÆäËûÖØÒªÊý¾Ý£¬ÀýÈçstack£¬ÔÚijЩ»·¾³ÖÐËüÊÇError¶ÔÏóµÄÒ»¸öÊôÐÔ¡£
ErrorsÒ²¿ÉÒÔÏñÆäËûÈκζÔÏóÒ»ÑùʹÓ㬲¢²»Ò»¶¨·ÇµÃÒªÅ׳öËûÃÇ£¬ÕâÒ²ÊÇËüÃÇΪʲô¶à´Î±»ÓÃ×÷»Øµ÷º¯ÊýµÄµÚÒ»¸ö²ÎÊý(Ë׳Æ
err first)¡£ ÔÚÏÂÃæµÄfs.readdir()Àý×ÓÖоÍÊÇÕâôÓõġ£
const fs = require('fs');
fs.readdir('/example/i-do-not-exist', function
callback(err, dirs) {
if (err instanceof Error) {
// `readdir` will throw an error because that
directory does not exist
// We will now be able to use the error object
passed by it in our callback function
console.log('Error Message: ' + err.message);
console.log('See? We can use Errors without
using try statements.');
} else {
console.log(dirs);
}
}); |
×îºó£¬ÔÚrejecting promisesʱҲ¿ÉÒÔʹÓÃError¶ÔÏó¡£ÕâʹµÃËü¸üÈÝÒ×´¦Àípromise
rejections£º
new Promise(function(resolve, reject) { reject(new Error('The promise was rejected.')); }).then(function() { console.log('I am an error.'); }).catch(function(err) { if (err instanceof Error) { console.log('The promise was rejected with an error.'); console.log('Error Message: ' + err.message); } }); |
²Ù×ݶÑÕ»¸ú×Ù
ÉÏÃæ†ªàÂÁËÄÇô¶à£¬Ñ¹ÖáµÄÖØÍ·Ï·À´ÁË£¬ÄǾÍÊÇÈçºÎ²Ù×ݶÑÕ»¸ú×Ù¡£
±¾ÕÂרÃÅÕë¶ÔÄÇЩÏñNodeJSÖ§Error.captureStackTraceµÄ»·¾³¡£
Error.captureStackTraceº¯Êý½ÓÊÜÒ»¸öobject×÷ΪµÚÒ»¸ö²ÎÊý£¬µÚ¶þ¸ö²ÎÊýÊÇ¿ÉÑ¡µÄ£¬½ÓÊÜÒ»¸öº¯Êý¡£capture
stack trace ²¶»ñµ±Ç°¶ÑÕ»¸ú×Ù£¬²¢ÔÚÄ¿±ê¶ÔÏóÖд´½¨Ò»¸östackÊôÐÔÀ´´æ´¢Ëü¡£Èç¹ûÌṩÁ˵ڶþ¸ö²ÎÊý£¬Ôò´«µÝµÄº¯Êý½«±»ÊÓΪµ÷ÓöÑÕ»µÄÖյ㣬Òò´Ë¶ÑÕ»¸ú×Ù½«½öÏÔʾµ÷Óøú¯Êý֮ǰ·¢ÉúµÄµ÷Óá£
ÈÃÎÒÃÇÓÃÀý×ÓÀ´ËµÃ÷ÕâÒ»µã¡£Ê×ÏÈ£¬ÎÒÃǽ«²¶»ñµ±Ç°¶ÑÕ»¸ú×Ù²¢½«Æä´æ´¢ÔÚ¹«¹²¶ÔÏóÖС£
const myObj = {};
function c() {
}
function b() {
// Here we will store the current stack trace
into myObj
Error.captureStackTrace(myObj);
c();
}
function a() {
b();
}
// First we will call these functions
a();
// Now let's see what is the stack trace stored
into myObj.stack
console.log(myObj.stack);
// This will print the following stack to the
console:
// at b (repl:3:7) <-- Since it was called
inside B, the B call is the last entry in the
stack
// at a (repl:2:1)
// at repl:1:1 <-- Node internals below this
line
// 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ÈëÕ»)£¬È»ºóÎÒÃÇaÖÐÓÖµ÷ÓÃÁËb(bÈëÕ»ÇÒÔÚaÖ®ÉÏ)¡£È»ºóÔÚbÖÐÎÒÃDz¶»ñÁ˵±Ç°¶ÑÕ»¼Ç¼²¢½«Æä´æ´¢ÔÚmyObjÖС£Òò´ËÔÚ¿ØÖÆÌ¨ÖвŻᰴÕÕb
aµÄ˳Ðò´òÓ¡¶ÑÕ»¡£
ÏÖÔÚÈÃÎÒÃǸøError.captureStackTrace´«µÝÒ»¸öº¯Êý×÷ΪµÚ¶þ¸ö²ÎÊý£¬¿´¿´»á·¢Éúʲô£º
const myObj = {};
function d() {
// Here we will store the current stack trace
into myObj
// This time we will hide all the frames after
`b` and `b` itself
Error.captureStackTrace(myObj, b);
}
function c() {
d();
}
function b() {
c();
}
function a() {
b();
}
// First we will call these functions
a();
// Now let's see what is the stack trace stored
into myObj.stack
console.log(myObj.stack);
// This will print the following stack to the
console:
// at a (repl:2:1) <-- As you can see here
we only get frames before `b` was called
// at repl:1:1 <-- Node internals below this
line
// 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.captureStackTraceFunctionʱ£¬ËüÒþ²ØÁËb±¾ÉíÒÔ¼°ËüÖ®ºóËùÓеĵ÷ÓÃÖ¡¡£Òò´Ë¿ØÖÆÌ¨½ö½ö´òÓ¡³öÒ»¸öa¡£
ÖÁ´ËÄãÓ¦¸Ã»áÎÊ×Ô¼º£º¡°Õâµ½µ×ÓÐʲôÓã¿¡±¡£Õâ·Ç³£ÓÐÓã¬ÒòΪÄã¿ÉÒÔÓÃËüÀ´Òþ²ØÓëÓû§Î޹صÄÄÚ²¿ÊµÏÖϸ½Ú¡£ÔÚChaiÖУ¬ÎÒÃÇʹÓÃËüÀ´±ÜÃâÏòÓû§ÏÔʾÎÒÃÇÊÇÈçºÎʵʩ¼ì²éºÍ¶ÏÑÔ±¾ÉíµÄ²»Ïà¹ØµÄϸ½Ú¡£
²Ù×÷¶ÑÕ»×·×Ùʵս
ÕýÈçÎÒÔÚÉÏÒ»½ÚÖÐÌáµ½µÄ£¬ChaiʹÓöÑÕ»²Ù×÷¼¼Êõʹ¶ÑÕ»¸ú×Ù¸ü¼ÓÓëÎÒÃǵÄÓû§Ïà¹Ø¡£ÏÂÃæ½«½ÒÏþÎÒÃÇÊÇÈçºÎ×öµ½µÄ¡£
Ê×ÏÈ£¬ÈÃÎÒÃÇÀ´¿´¿´µ±¶ÏÑÔʧ°ÜʱÅ׳öµÄAssertionErrorµÄ¹¹Ô캯Êý£º
// `ssfi` stands for "start stack function". It is the reference to the// starting point for removing irrelevant frames from the stack trace function AssertionError (message, _props, ssf) { var extend = exclude('name', 'message', 'stack', 'constructor', 'toJSON') , props = extend(_props || {});
// Default values
this.message = message || 'Unspecified AssertionError';
this.showDiff = false;
// Copy from properties
for (var key in props) {
this[key] = props[key];
}
// Here is what is relevant for us:
// If a start stack function was provided we
capture the current stack trace and pass
// it to the `captureStackTrace` function so
we can remove frames that come after it
ssf = ssf || arguments.callee;
if (ssf && Error.captureStackTrace)
{
Error.captureStackTrace(this, ssf);
} else {
// If no start stack function was provided we
just use the original stack property
try {
throw new Error();
} catch(e) {
this.stack = e.stack;
}
}
} |
ÈçÄãËù¼û£¬ÎÒÃÇʹÓÃError.captureStackTrace²¶»ñ¶ÑÕ»×·×Ù²¢½«Ëü´æ´¢ÔÚÎÒÃÇÕýÔÚ´´½¨µÄAssertErrorʵÀýÖУ¨Èç¹û´æÔڵϰ£©£¬È»ºóÎÒÃǽ«Ò»¸öÆðʼ¶ÑÕ»º¯Êý´«µÝ¸øËü£¬ÒÔ±ã´Ó¶ÑÕ»¸ú×ÙÖÐɾ³ý²»Ïà¹ØµÄµ÷ÓÃÖ¡£¬ËüÖ»ÏÔʾChaiµÄÄÚ²¿ÊµÏÖϸ½Ú£¬×îÖÕʹ¶ÑÕ»±äµÃÇåÎúÃ÷ÁË¡£
ÏÖÔÚÈÃÎÒÃÇÀ´¿´¿´@meeberÔÚÕâ¸öÁîÈ˾ªÌ¾µÄPRÖÐÌá½»µÄ´úÂë¡£
ÔÚÄ㿪ʼ¿´ÏÂÃæµÄ´úÂë֮ǰ£¬ÎÒ±ØÐë¸æËßÄãaddChainableMethod·½·¨ÊǸÉɶµÄ¡£Ëü½«´«µÝ¸øËüµÄÁ´Ê½·½·¨Ìí¼Óµ½¶ÏÑÔÉÏ£¬ËüÒ²Óðüº¬¶ÏÑԵķ½·¨±ê¼Ç¶ÏÑÔ±¾Éí£¬²¢½«Æä±£´æÔÚ±äÁ¿ssfi(Æô¶¯¶ÑÕ»º¯Êýָʾ·û)ÖС£ÕâÒ²¾ÍÒâζ×ŵ±Ç°¶ÏÑÔ½«»áÊǶÑÕ»ÖеÄ×îºóÒ»¸öµ÷ÓÃÖ¡£¬Òò´ËÎÒÃDz»»áÔÚ¶ÑÕ»ÖÐÏÔʾChaiÖеÄÈκνøÒ»²½µÄÄÚ²¿·½·¨¡£ÎÒûÓÐÌí¼ÓÕû¸ö´úÂ룬ÒòΪËü×öÁ˺ܶàÊÂÇ飬Óе㼬ÊÖ£¬µ«Èç¹ûÄãÏë¶ÁËü£¬µãÎÒÔĶÁ¡£
ÏÂÃæµÄÕâ¸ö´úÂëÆ¬¶ÎÖУ¬ÎÒÃÇÓÐÒ»¸ölengOf¶ÏÑÔµÄÂß¼£¬Ëü¼ì²éÒ»¸ö¶ÔÏóÊÇ·ñÓÐÒ»¶¨µÄlength¡£ÎÒÃÇÏ£ÍûÓû§¿ÉÒÔÏñÕâÑùÀ´Ê¹ÓÃËü
function assertLength (n, msg) { if (msg) flag(this, 'message', msg); var obj = flag(this, 'object') , ssfi = flag(this, 'ssfi');
// Pay close attention to this line
new Assertion(obj, msg, ssfi, true).to.have.property('length');
var len = obj.length;
// This line is also relevant
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
);
}
Assertion.addChainableMethod('lengthOf', assertLength,
assertLengthChain); |
ÔÚÉÏÃæµÄ´úÂëÆ¬¶ÎÖУ¬ÎÒÍ»³öÇ¿µ÷ÁËÓëÎÒÃÇÏÖÔÚÏà¹ØµÄ´úÂë¡£ÈÃÎÒÃÇ´Óµ÷ÓÃthis.assert¿ªÊ¼ËµÆð¡£
ÒÔÏÂÊÇthis.assert·½·¨µÄÔ´´úÂ룺
Assertion.prototype.assert = function (expr, msg, negateMsg, expected, _actual, showDiff) { var ok = util.test(this, arguments); if (false !== showDiff) showDiff = true; if (undefined === expected && undefined === _actual) showDiff = false; if (true !== config.showDiff) showDiff = false;
if (!ok) {
msg = util.getMessage(this, arguments);
var actual = util.getActual(this, arguments);
// This is the relevant line for us
throw new AssertionError(msg, {
actual: actual
, expected: expected
, showDiff: showDiff
}, (config.includeStack) ? this.assert : flag(this,
'ssfi'));
}
}; |
assert·½·¨¸ºÔð¼ì²é¶ÏÑÔ²¼¶û±í´ïʽÊÇ·ñͨ¹ý¡£Èç¹û²»Í¨¹ý£¬ÎÒÃÇÔòʵÀý»¯Ò»¸öAssertionError¡£²»ÖªµÀÄã×¢Ò⵽û£¬ÔÚʵÀý»¯AssertionErrorʱ£¬ÎÒÃÇÒ²¸øËü´«µÝÁËÒ»¸ö¶ÑÕ»×·×Ùº¯ÊýָʾÆ÷(ssfi)£¬Èç¹ûÅäÖõÄincludeStack´¦ÓÚ¿ªÆô״̬£¬ÎÒÃÇͨ¹ý½«this.assert±¾Éí´«µÝ¸øËüÀ´ÎªÓû§ÏÔʾÕû¸ö¶ÑÕ»¸ú×Ù¡£·´Ö®£¬ÎÒÃÇÔòÖ»ÏÔʾssfi±ê¼ÇÖд洢µÄÄÚÈÝ£¬Òþ²Øµô¶ÑÕ»¸ú×ÙÖиü¶àµÄÄÚ²¿ÊµÏÖϸ½Ú¡£
ÏÖÔÚÈÃÎÒÃÇÀ´ÌÖÂÛÏÂÒ»ÐкÍÎÒÃÇÏà¹ØµÄ´úÂë°É£º
`new Assertion (obj, msg, ssfi, true).to.have.property('length');` |
As you can see here we are passing the content we¡¯ve
got from the ssfi flag when creating our nested assertion.
This means that when the new assertion gets created
it will use this function as the starting point for
removing unuseful frames from the stack trace. By
the way, this is the Assertion constructor: ÈçÄãËù¼û£¬ÎÒÃÇÔÚ´´½¨Ç¶Ì×¶ÏÑÔʱ½«´Óssfi±ê¼ÇÖеÄÄÚÈÝ´«µÝ¸øÁËËü¡£ÕâÒâζ×Åд´½¨µÄ¶ÏÑÔ»áʹÓÃÄǸö·½·¨×÷ΪÆðʼµ÷ÓÃÖ¡£¬´Ó¶ø¿ÉÒÔ´Ó¶ÑÕ»×·×ÙÖÐÇå³ýûÓеĵ÷ÓÃÕ»¡£Ë³±ãÒ²¿´ÏÂAssertionµÄ¹¹ÔìÆ÷°É£º
function Assertion (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);
return util.proxify(this);
} |
²»ÖªµÀÄãÊÇ·ñ»¹¼ÇµÄÎÒÏÈǰ˵¹ýµÄaddChainableMethod·½·¨£¬ËüʹÓÃ×Ô¼ºµÄ¸¸¼¶·½·¨ÉèÖÃssfi±êÖ¾£¬ÕâÒâζ×ÅËüʼÖÕ´¦ÓÚ¶ÑÕ»µÄµ×²¿£¬ÎÒÃÇ¿ÉÒÔɾ³ýËüÖ®ÉϵÄËùÓе÷ÓÃÖ¡¡£
ͨ¹ý½«ssfi´«µÝ¸øÇ¶Ì×¶ÏÑÔ£¬ËüÖ»¼ì²éÎÒÃǵĶÔÏóÊÇ·ñ¾ßÓ㤶ÈÊôÐÔ£¬ÎÒÃǾͿÉÒÔ±ÜÃâÖØÖÃÎÒÃǽ«ÒªÓÃ×÷Æðʼָ±êÆ÷µÄµ÷ÓÃÖ¡£¬È»ºóÔÚ¶ÑÕ»ÖпÉÒÔ¿´µ½ÒÔǰµÄaddChainableMethod¡£
Õâ¿ÉÄÜ¿´ÆðÀ´Óе㸴ÔÓ£¬ËùÒÔÈÃÎÒÃǻعËÒ»ÏÂÎÒÃÇÏë´ÓÕ»ÖÐɾ³ýÎÞÓõĵ÷ÓÃ֡ʱChaiÖÐËù·¢ÉúµÄÊÂÇ飺
µ±ÎÒÃÇÔËÐжÏÑÔʱ£¬ÎÒÃǽ«Ëü×Ô¼ºµÄ·½·¨×÷ÎªÒÆ³ý¶ÑÕ»ÖеÄÏÂÒ»¸öµ÷ÓÃÖ¡µÄ²Î¿¼
¶ÏÑÔʧ°Üʱ£¬ÎÒÃÇ»áÒÆ³ýËùÓÐÎÒÃÇÔڲο¼Ö¡Ö®ºó±£´æµÄÄÚ²¿µ÷ÓÃÖ¡¡£
Èç¹û´æÔÚǶÌ׵ĶÏÑÔ¡£ÎÒÃDZØÐëÒÀ¾ÉʹÓõ±Ç°¶ÏÑԵĸ¸·½·¨×÷Ϊɾ³ýÏÂÒ»¸öµ÷ÓÃÖ¡µÄ²Î¿¼µã£¬Òò´ËÎÒÃǰѵ±Ç°µÄssfi£¨Æðʼº¯ÊýָʾÆ÷£©´«µÝ¸øÎÒÃÇËù´´½¨µÄ¶ÏÑÔ£¬ÒÔ±ãËü¿ÉÒÔ±£´æ¡£
|