Skip to content

Refactor prioritizeAndRun method for performance optimization and readability enhancement #368

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 22 additions & 41 deletions src/rule.js
Original file line number Diff line number Diff line change
Expand Up @@ -265,50 +265,31 @@ class Rule extends EventEmitter {
* @return {Promise(boolean)} rule evaluation result
*/
const prioritizeAndRun = (conditions, operator) => {
if (conditions.length === 0) {
return Promise.resolve(true)
}
if (conditions.length === 1) {
// no prioritizing is necessary, just evaluate the single condition
// 'all' and 'any' will give the same results with a single condition so no method is necessary
// this also covers the 'not' case which should only ever have a single condition
return evaluateCondition(conditions[0])
}
let method = Array.prototype.some
if (operator === 'all') {
method = Array.prototype.every
}
const orderedSets = this.prioritizeConditions(conditions)
let cursor = Promise.resolve()
// use for() loop over Array.forEach to support IE8 without polyfill
for (let i = 0; i < orderedSets.length; i++) {
const set = orderedSets[i]
let stop = false
cursor = cursor.then((setResult) => {
// after the first set succeeds, don't fire off the remaining promises
if ((operator === 'any' && setResult === true) || stop) {
debug(
'prioritizeAndRun::detected truthy result; skipping remaining conditions'
)
stop = true
return true
}

// after the first set fails, don't fire off the remaining promises
if ((operator === 'all' && setResult === false) || stop) {
debug(
'prioritizeAndRun::detected falsey result; skipping remaining conditions'
)
stop = true
return false
if (conditions.length === 0) return Promise.resolve(true);
if (conditions.length === 1) return evaluateCondition(conditions[0]);

const method = operator === 'all' ? Array.prototype.every : Array.prototype.some;
const orderedSets = this.prioritizeConditions(conditions);
let stop = false;

const cursor = orderedSets.reduce((promise, set) => {
return promise.then((setResult) => {
if (stop) return setResult;

const shouldStop = (operator === 'any' && setResult === true) || (operator === 'all' && setResult === false);
if (shouldStop) {
stop = true;
return setResult;
}
// all conditions passed; proceed with running next set in parallel
return evaluateConditions(set, method)
})
}
return cursor

return evaluateConditions(set, method);
});
}, Promise.resolve());

return cursor;
}


/**
* Runs an 'any' boolean operator on an array of conditions
* @param {Condition[]} conditions to be evaluated
Expand Down