diff options
author | Michael Leibman <michael.leibman@gmail.com> | 2011-10-31 19:45:29 -0700 |
---|---|---|
committer | Michael Leibman <michael.leibman@gmail.com> | 2011-10-31 19:45:29 -0700 |
commit | 5a5a6a7c616ad42cfe05a99ac92b2d01254b0885 (patch) | |
tree | d77ca9c2d282f995c71a3b505d3c4c6e41d616e6 /slick.dataview.js | |
parent | a4d5cfd3375287be8bd41e3b7dae772fa517cddf (diff) | |
download | SlickGrid-5a5a6a7c616ad42cfe05a99ac92b2d01254b0885.zip SlickGrid-5a5a6a7c616ad42cfe05a99ac92b2d01254b0885.tar.gz SlickGrid-5a5a6a7c616ad42cfe05a99ac92b2d01254b0885.tar.bz2 |
Continuation of DataView perf work
- Reverted the batched filter functions and implemented dynamic
recompilation instead.
- Added compilation of an optimized filter loop for the
"isFilterExpanding" hint.
Diffstat (limited to 'slick.dataview.js')
-rw-r--r-- | slick.dataview.js | 114 |
1 files changed, 84 insertions, 30 deletions
diff --git a/slick.dataview.js b/slick.dataview.js index 94d3018..56370ce 100644 --- a/slick.dataview.js +++ b/slick.dataview.js @@ -23,8 +23,7 @@ var self = this; var defaults = { - groupItemMetadataProvider: null, - batchFilter: false + groupItemMetadataProvider: null }; @@ -44,6 +43,9 @@ var prevRefreshHints = {}; var filterArgs; var filteredItems = []; + var compiledFilter; + var compiledFilterWithCaching; + var filterCache = []; // grouping var groupingGetter; @@ -181,6 +183,8 @@ function setFilter(filterFn) { filter = filterFn; + compiledFilter = compileFilter(); + compiledFilterWithCaching = compileFilterWithCaching(); refresh(); } @@ -316,7 +320,7 @@ var group; var val; var groups = []; - var groupsByVal = {}; + var groupsByVal = []; var r; for (var i = 0, l = rows.length; i < l; i++) { @@ -339,20 +343,6 @@ return groups; } - function compileAccumulatorLoop(aggregator) { - var fnRegex = /^function[^(]*\(([^)]*)\)\s*{([\s\S]*)}$/; - var fnParts = aggregator.accumulate.toString().match(fnRegex); - var itemParamName = fnParts[1], body = fnParts[2]; - - return new Function( - "_items", - "for (var " + itemParamName + ", _i=0, _il=_items.length; _i<_il; _i++) {" + - itemParamName + " = _items[_i]; " + - body + - "}" - ); - } - // TODO: lazy totals calculation function calculateGroupTotals(group) { if (group.collapsed && !aggregateCollapsed) { @@ -407,28 +397,87 @@ return groupedRows; } - // TODO: inline filter execution similar to accumulators - function getBatchFilteringFn() { - return function(data, args) { - var item, retval = [], idx = 0; - for (var i = 0, il = data.length; i < il; i++) { - item = data[i]; - if (filter(item)) { - retval[idx++] = item; + function getFunctionInfo(fn) { + var fnRegex = /^function[^(]*\(([^)]*)\)\s*{([\s\S]*)}$/; + var matches = fn.toString().match(fnRegex); + return { + params: matches[1].split(","), + body: matches[2] + }; + } + + function compileAccumulatorLoop(aggregator) { + var accumulatorInfo = getFunctionInfo(aggregator.accumulate); + + return new Function( + "_items", + "for (var " + accumulatorInfo.params[0] + ", _i=0, _il=_items.length; _i<_il; _i++) {" + + accumulatorInfo.params[0] + " = _items[_i]; " + + accumulatorInfo.body + + "}" + ); + } + + function compileFilter() { + var filterInfo = getFunctionInfo(filter); + + var filterBody = filterInfo.body.replace(/return ([^;]+?);/gi, + "if ($1) { _retval[_idx++] = $item$; }; continue;"); + + var fnTemplate = function(_items, _args) { + var _retval = [], _idx = 0; + var $item$, $args$ = _args; + for (var _i = 0, _il = _items.length; _i < _il; _i++) { + $item$ = _items[_i]; + $filter$; + } + return _retval; + }; + + var tpl = getFunctionInfo(fnTemplate).body; + tpl = tpl.replace(/\$filter\$/gi, filterBody); + tpl = tpl.replace(/\$item\$/gi, filterInfo.params[0]); + tpl = tpl.replace(/\$args\$/gi, filterInfo.params[1]); + + return new Function("_items,_args", tpl); + } + + function compileFilterWithCaching() { + var filterInfo = getFunctionInfo(filter); + + var filterBody = filterInfo.body.replace(/return ([^;]+?);/gi, + "if ((_cache[_i] = $1)) { _retval[_idx++] = $item$; }; continue;"); + + var fnTemplate = function(_items, _args, _cache) { + var _retval = [], _idx = 0; + var $item$, $args$ = _args; + for (var _i = 0, _il = _items.length; _i < _il; _i++) { + $item$ = _items[_i]; + if (_cache[_i]) { + _retval[_idx++] = $item$; + continue; } + $filter$; } - return retval; + return _retval; }; + + var tpl = getFunctionInfo(fnTemplate).body; + tpl = tpl.replace(/\$filter\$/gi, filterBody); + tpl = tpl.replace(/\$item\$/gi, filterInfo.params[0]); + tpl = tpl.replace(/\$args\$/gi, filterInfo.params[1]); + + return new Function("_items,_args,_cache", tpl); } function getFilteredAndPagedItems(items) { if (filter && !refreshHints.isFilterUnchanged) { - var filterFn = options.batchFilter ? filter : getBatchFilteringFn(); - if (refreshHints.isFilterNarrowing) { - filteredItems = filterFn(filteredItems, filterArgs); + filteredItems = compiledFilter(filteredItems, filterArgs); + } else if (refreshHints.isFilterExpanding) { + filteredItems = compiledFilterWithCaching(items, filterArgs, filterCache); } else { - filteredItems = filterFn(items, filterArgs); + filteredItems = compiledFilter(items, filterArgs); } } else { // special case: if not filtering and not paging, the resulting @@ -495,6 +544,11 @@ function recalc(_items) { rowsById = null; + if (refreshHints.isFilterNarrowing != prevRefreshHints.isFilterNarrowing || + refreshHints.isFilterExpanding != prevRefreshHints.isFilterExpanding) { + filterCache = []; + } + var filteredItems = getFilteredAndPagedItems(_items); totalRows = filteredItems.totalRows; var newRows = filteredItems.rows; |