lijia4

JavaScript performance comparison

Revision 9 of this test case created

Preparation code

        <canvas id="board" width="950" height="120"></canvas>
<script>
Benchmark.prototype.setup = function() {
    (function (global) {
        "use strict";
   
        var cal = {};
   
        function List(link) {
            this.begin = link;
            this.iterator = link;
        }
   
        List.prototype.advance = function () {
            this.iterator = this.iterator.next;
            return this.iterator;
        }
   
        List.prototype.retreat = function () {
            this.iterator = this.iterator.prev;
            return this.iterator;
        }
   
        function Link() {
            this.prev = null;
            this.next = null;
        }
   
        Link.prototype.push_back = function (link) {
            if (this.next) {
                link.next = this.next;
                this.next.prev = link;
            }
            this.next = link;
            link.prev = this;
            return link;
        }
   
        Link.prototype.push_front = function (link) {
            link.next = this;
            this.prev = link;
            return link;
        }//defintion not complete
   
        var tType = {
            empty: -1,
            letters: 0,
            numbers: 1,
            operators: 2,
            exponentiation: 3,
            logarithm: 4,
            root: 5,
            fration: 6
        };
   
        function init() {
            cal.printer.init();
            document.addEventListener("keydown", cal.get, false);
        }
   
        cal.tType = tType;
   
        cal.List = List;
   
        cal.Link = Link;
   
        cal.init = init;
   
        window.cal = cal;
   
    })(window);
   
    (function (cal) {
        "use strict";
   
        var printer = {};
   
        var ctx;
   
        var x = 10, y = 70, size = 40;
   
        var tType = cal.tType;
   
        var bType = {
            none: 0,
            upperbound: 1,
            lowerbound: 2
        }
   
        function BoxModel(size) {
            this.width = 0;
            this.baseline = 0;
            this.upperbound = getTextHeight(size);
            this.lowerbound = 0;
        }
   
        BoxModel.prototype = new cal.Link();
   
        BoxModel.prototype.height = function () {
            return this.upperbound - this.lowerbound;
        }
   
        var bl = new cal.List(new BoxModel(size));
   
        function setter() {
            this.buffer = 0;
        }
        setter.prototype.set = function (size) {
            this.buffer = size;
            ctx.font = size + "px times";
        }
        setter.prototype.restore = function () {
            ctx.font = this.buffer + "px times";
        }
   
        var styleControl = new setter();
   
        function clear(box) {
            ctx.clearRect(x, y - box.upperbound - 30, box.width, 100);
        }//need revision
   
        function mix(compass, func) {
            var computedStyle = func(compass.size);
            return {
                x: compass.x,
                y: compass.y - computedStyle.elev,
                size: computedStyle.size
            }
        }
   
        function getTextHeight(size) {
            return Math.floor(size * 0.8);
        }
   
        function getLogStyle(size) {
            return {
                size: Math.floor(size * 0.4),
                elev: -Math.floor(size * 0.2)
            }
        }
   
        function getExponentStyle(size) {
            return {
                size: Math.floor(size * 0.7),
                elev: Math.floor(size * 0.65)
            }
        }
   
        function getFrationStyle(size) {
            return {
                size: Math.floor(size * 0.8),
                elev: Math.floor(size * 0.4),
                gap: Math.floor(size * 0.1)
            }
        }
   
        function getIndexStyle(size) {
            return {
                size: Math.floor(size * 0.4),
                elev: Math.floor(size * 0.4),
            }
        }
   
        function getRadicandStyle(size) {
            return {
                size: Math.floor(size * 0.8),
                gap: Math.floor(size * 0.2)
            }
        }
   
        function drawLine(x, y, d) {
            ctx.beginPath();
            ctx.moveTo(x, y);
            ctx.lineTo(x + d, y);
            ctx.stroke();
        }
   
        function drawText(token, compass) {
            ctx.fillText(token.value, compass.x, compass.y);
            compass.x += token.style.width;
        }
   
        function print(token, compass) {
            styleControl.set(compass.size);
            while (token) {
                switch (token.type) {
                    case tType.root:
                        compass.x = p_root(token, compass);
                        break;
                    case tType.fration:
                        compass.x = p_fration(token, compass);
                        break;
                    case tType.exponentiation:
                        compass.x = print(token.exponent, mix(compass, getExponentStyle));
                        break;
                    case tType.logarithm:
                        drawText(token, compass);
                        compass.x = print(token.base, mix(compass, getLogStyle));
                        break;
                    default:
                        drawText(token, compass);
                        break;
                }
                token = token.next;
            }
            styleControl.restore();
            return compass.x;
        }
   
        function p_root(token, compass) {
            var iterator;
            var width = token.style.width;
            var computedStyle1 = getIndexStyle(size);
            var computedStyle2 = getRadicandStyle(size);
            if (token.index.type != tType.empty) {
                iterator = bl.advance();
                print(token.index, {
                    x: compass.x + (width - iterator.width) / 2,
                    y: compass.y - computedStyle1.elev - iterator.baseline,
                    size: computedStyle1.size
                });
            }
            if (token.radicand.type != tType.empty) {
                iterator = bl.advance();
                print(token.radicand, {
                    x: compass.x + (width - iterator.width) / 2,
                    y: compass.y,
                    size: computedStyle2.size
                });
            }
   
            if (iterator) {
                drawLine(compass.x,
                    compass.y - iterator.upperbound - computedStyle2.gap,
                    Math.max(compass.size, iterator.width));
            }
            else {
                drawLine(compass.x,
                    compass.y - getTextHeight(computedStyle2.size) - computedStyle2.gap,
                    compass.size);
            }
            return width;
        }
   
        function p_fration(token, compass) {
            var iterator;
            var width = token.style.width;
            var computedStyle = getFrationStyle(compass.size);
            if (token.numerator.type != tType.empty) {
                iterator = bl.advance();
                print(token.numerator, {
                    x: compass.x + (width - iterator.width) / 2,
                    y: compass.y - computedStyle.elev - computedStyle.gap - iterator.baseline,
                    size: computedStyle.size
                });
            }
            if (token.denominator.type != tType.empty) {
                iterator = bl.advance();
                print(token.denominator, {
                    x: compass.x + (width - iterator.width) / 2,
                    y: compass.y - computedStyle.elev + computedStyle.gap +
                        getTextHeight(computedStyle.size) - iterator.baseline,
                    size: computedStyle.size
                });
            }
            drawLine(compass.x, compass.y - computedStyle.elev, width);
            return width;
        }
   
        function measure(token, box, size, boundType) {
            styleControl.set(size);
            while (token) {
                switch (token.type) {
                    case tType.root:
                        m_root(token, box, size, boundType);
                        break;
                    case tType.fration:
                        m_fration(token, box, size, boundType);
                        break;
                    case tType.exponentiation:
                        m_exponent(token, box, size, boundType);
                        break;
                    case tType.logarithm:
                        token.style.width = ctx.measureText(token.value).width;//temporary measure
                        m_log(token, box, size, boundType);
                        break;
                    default:
                        token.style.width = ctx.measureText(token.value).width;//temporary measure
                        box.width += token.style.width;
                        break;
                }
                token = token.next;
            }
            styleControl.restore();
        }
   
        function m_fration(token, box, size, boundType) {
            var computedStyle = getFrationStyle(size);
            var box1 = new BoxModel(computedStyle.size);
            var box2 = new BoxModel(computedStyle.size);
   
            if (token.numerator.type != tType.empty) {
                box.push_back(box1);
                measure(token.numerator, box1, computedStyle.size,
                    boundType == bType.none ? bType.lowerbound : boundType);
            }
            if (token.denominator.type != tType.empty) {
                box.push_back(box2);
                measure(token.denominator, box2, computedStyle.size,
                    boundType == bType.none ? bType.upperbound : boundType);
            }
   
            token.style.width = Math.max(box1.width, box2.width, size);
            box.width += token.style.width;
   
            m_aggregate(box, boundType,
                box.baseline + computedStyle.elev + box1.height() + computedStyle.gap,
                box.baseline + computedStyle.elev - box2.height() - computedStyle.gap);
        }
   
        function m_log(token, box, size, boundType) {
            var computedStyle = getLogStyle(size);
            var box1 = new BoxModel(computedStyle.size);
            if (token.base.type != cal.tType.empty) {
                measure(token.base, box1, computedStyle.size, bType.none);
            }
   
            box.width += box1.width + token.style.width;
   
            m_aggregate(box, boundType,
                box1.upperbound + computedStyle.elev + box.baseline,
                box1.lowerbound + computedStyle.elev + box.baseline);
        }
   
        function m_exponent(token, box, size, boundType) {
            var computedStyle = getExponentStyle(size);
            var box1 = new BoxModel(computedStyle.size);
            if (token.exponent.type != cal.tType.empty) {
                measure(token.exponent, box1, computedStyle.size, bType.none);
            }
   
            box.width += box1.width;
   
            m_aggregate(box, boundType,
                 box.baseline + computedStyle.elev + box1.upperbound,
                 box.baseline + computedStyle.elev + box1.lowerbound);
        }
   
        function m_root(token, box, size, boundType) {
            var computedStyle1 = getIndexStyle(size);
            var computedStyle2 = getRadicandStyle(size);
            var box1 = new BoxModel(computedStyle1.size);
            var box2 = new BoxModel(computedStyle2.size);
   
            if (token.index.type != tType.empty) {
                box.push_back(box1);
                measure(token.index, box1, computedStyle1.size,
                    boundType == bType.none ? bType.lowerbound : boundType);
            }
   
            if (token.radicand.type != tType.empty) {
                box.push_back(box2);
                measure(token.radicand, box2, computedStyle2.size, bType.none);
            }
   
            token.style.width = Math.max(box2.width, size);
            box.width += token.style.width;
   
            m_aggregate(box, boundType,
                Math.max(box.baseline + computedStyle1.elev + box1.height(),
                box.baseline + box2.upperbound + computedStyle2.gap),
                box.baseline + box2.lowerbound);
        }
   
        function m_aggregate(box, boundType, hi, lo) {
            if (hi > box.upperbound) {
                if (boundType == bType.upperbound) {
                    box.baseline += box.upperbound - hi;
                }
                box.upperbound = hi;
            }
            if (lo < box.lowerbound) {
                if (boundType == bType.lowerbound) {
                    box.baseline -= lo;
                }
                box.lowerbound = lo;
            }
        }
   
        function update(token) {
            clear(bl.begin);
            bl = new cal.List(new BoxModel(size));
            measure(token, bl.begin, size, bType.none);
            print(token, { x: x, y: y, size: size });
        }
   
        function init() {
            ctx = board.getContext("2d");
        }
   
        printer.update = update;
   
        printer.init = init;
   
        cal.printer = printer;
   
    })(cal);
   
    var asd;
    (function (cal) {
        "use strict";
   
        var tType = cal.tType;
   
        var dType = {
            none: 0,
            left: 1,
            right: 2,
        };
   
        function Token(value, type) {
            this.value = value;
            this.type = type;
            this.style = { width: 0 };
        }
   
        Token.prototype = new cal.Link();
   
        Token.prototype.setup = function (value, type) {
            this.value = value;
            this.type = type;
        }
   
        Token.prototype.add = function (input, index) {
            var str = this.value;
            str = str.substring(0, index) + input + str.substring(index);
            this.value = str;
        }
   
        Token.prototype.split = function (input, index) {
   
        }
   
        function TokenList() {
            this.index = 0;
            this.context = [];
        }
   
        TokenList.prototype = new cal.List(new Token("", tType.empty));
   
        TokenList.prototype.read = function (input) {
            var type = getType(input);
            var iterator = this.iterator;
   
            if (this.index == 0) {
                if (isSociable(type)) {
                    if (type == iterator.type && iterator.type != tType.empty) {
                        iterator.push_front(new Token("", tType.empty));
                        iterator = this.retreat();
                    }
                    else if (iterator.prev && type == iterator.prev.type) {
                        iterator = this.retreat();
                    }
                }
                else {
                    iterator.push_front(new Token("", tType.empty));
                    iterator = this.retreat();
                }
            }
            else if (this.index == iterator.value.length) {
                if (isSociable(type)) {
                    if (type != iterator.type) {
                        iterator.push_back(new Token("", tType.empty));
                        iterator = this.advance();
                    }
                    else if (iterator.next && type == iterator.next.type) {
                        iterator = this.advance();
                    }
                }
                else {
                    iterator.push_back(new Token("", tType.empty));
                    iterator = this.advance();
                }
            }
   
            if (type == iterator.type) {
                iterator.add(input, this.index);
                this.index++;
            }
            else if (iterator.type == tType.empty) {
                iterator.setup(input, type);
                this.index = 1;
            }
            else {
                iterator.split(input, this.index);
                this.index = 1;
            }
   
            this.iterator = this.check(iterator);
        }
   
        TokenList.prototype.check = function (token) {
            switch (token.value) {
                case "sqrt":
                    this.index = 0;
                    this.context.push(token);
                    token.type = tType.root;
                    token.index = new Token("", tType.empty);
                    token.radicand = new Token("", tType.empty);
                    return token.radicand;
                case "^":
                    this.index = 0;
                    this.context.push(token);
                    token.type = tType.exponentiation;
                    token.exponent = new Token("", tType.empty);
                    return token.exponent;
                case "slash":
                    this.index = 0;
                    this.context.push(token);
                    token.type = tType.fration;
                    token.numerator = new Token("", tType.empty);
                    token.denominator = new Token("", tType.empty);
                    return token.denominator;
                case "log":
                    this.index = 0;
                    this.context.push(token);
                    token.type = tType.logarithm;
                    token.base = new Token("", tType.empty);
                    return token.base;
            }
            return token;
        }
   
        var t = new TokenList();
   
        asd = t.begin;
   
        function getType(char) {
            var code = char.charCodeAt(0);
            if (code >= 48 && code <= 57 || code == 46) {
                return tType.numbers;
            }
            else if (code >= 97 && code <= 122) {
                return tType.letters;
            }
            else if (code == 94) {
                return tType.exponentiation;
            }
            else {
                return tType.operators;
            }
        }
   
        function isSociable(type) {
            switch (type) {
                case tType.operators:
                case tType.exponentiation:
                    return false;
                default:
                    return true;
            }
        }
   
        function get(e) {
            var input = e.key;
            if (input.length > 1) {
                switch (input) {
                    case "Enter":
                        Enter();
                        break;
                    case "Backspace":
                        BackSpace();
                        break;
                    case "Left":
                        GoLeft();
                        break;
                    case "Right":
                        GoRight();
                        break;
                    case "Up":
                        GoTop();
                        break;
                    case "Down":
                        GoBot();
                        break;
                }
            }
            else {
                t.read(input);
                cal.printer.update(t.begin);
            }
        }
   
   
        cal.get = get;
   
    })(cal);
    cal.init();
   
};
</script>

Preparation code output

Test runner

Warning! For accurate results, please disable Firebug before running the tests. (Why?)

Java applet disabled.

Testing in unknown unknown
Test Ops/sec
1
cal.get({key:"1"});
pending…
2
if(a==[]){}
pending…

Compare results of other browsers

Revisions

You can edit these tests or add even more tests to this page by appending /edit to the URL. Here’s a list of current revisions for this page:

0 comments

Add a comment