简体   繁体   中英

Assertions in JavaScript

Extensively reading about various assertion frameworks in JavaScript. Is there any kind of de-facto/most common "standard" library/framework? When selecting one - which points are most worth noticing?

The (only) requirement I can think about is close-to-zero performance overhead when in production mode.

Two possible solutions:

Have your build release script remove the Assert lines.

or

Have your build script override the Assert function so it is just an empty function. Downside to this is if you assert call has logic in it [aka assert( x > 100 , "foo" )] than that logic [x > 100] is still going to be run.

Here is what I use:

When I'm working on the code I have initDevMode(); at the top of the file I'm working with, and when I'm ready to release to production, I just remove that line and all the asserts just go to an empty function.

/**
 * Log a message to console:
 *  either use jquery's console.error
 *  or a thrown exception.
 *  
 *  call initDevMode(); before use to activate
 *  use with:
 *      assert(<condition>, "message");
 *      eg: assert(1 != 1, "uh oh!");
 *  
 *  Log errors with:
 *       errorLog(message);
 *       eg: errorLog(xhr.status);
 */
assert = function(test, msg) { }
errorLog =function(msg) { }

initDevMode = function() {
    assert = function(test, msg) {
        msg = msg || "(no error message)";
        if(!test) {
            try {
                    throw Error();
                } catch(e) {
                    var foo = e;
                    var lines = e.stack.split('\n');
                    for(i in lines) {
                        if(i > 2) {
                        errorLog(msg + lines[i]);
                    }
                }
            }
        }
        throw("Assertion failed with: " + msg);
    };
    errorLog = function(msg) {
        if(typeof console.error == 'function') { 
            console.error(msg);
        } else {
            function errorLog(msg) {
                console.log("foo");
                setTimeout(function() {
                    throw new Error(msg);
                }, 0);
            }
        }
    };
}

I use the following to replace console.assert when it's unavailable for whatever reason.

It's definitely not a de-facto standard, and it is far from ideal, but it does satisfy your requirement that the assertion not be evaluated in production mode. Also, it shows you the expression that triggered the failed assertion, which aids debugging.

The screwy calling syntax (with a function expression) is there to create a closure, so that the assert function has access to the same variables that its caller had access to.

I suspect that this has high compile-time and run-time overhead, but I haven't attempted to verify that.

function assert(func) {
    var name;
    if (typeof(ENABLE_ASSERTIONS) !== "undefined" && !ENABLE_ASSERTIONS) {
        return;
    }
    name = arguments.callee.caller;
    name = name ? name.name : "(toplevel)";
    if (!func()) {
        throw name + ": assertion failed: " + ('' + func).replace(/function[^(]*\([^)]*\)[^{]*{[^r]*return/, '').replace(/;[ \t\n]*}[ \t\n]*$/, '');
    }
}

Using it looks like:

function testAssertSuccess() {
    var i = 1;
    assert(function() { return i === 1; });
}
function testAssertFailure() {
    var j = 1;
    assert(function() { return j === 2; });
}
ENABLE_ASSERTIONS = true;
testAssertSuccess();
testAssertFailure();

HTH!

Take a look to Jascree ; basically it is a tool that can remove assertions with almost arbitrary logic from your code. It is handy to use as a batch processor to generate your production code or for a fastcgi-backed scripts directory that you can use when you need to test performance/profile your code.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM