Skip to content
Merged
Show file tree
Hide file tree
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
92 changes: 92 additions & 0 deletions test/test-reentrancy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
const test = require("node:test");
const assert = require("node:assert/strict");
const { setImmediate } = require("node:timers/promises");
const when = require("../");

test("clear inside a false predicate stops future checks", async (t) => {
let checks = 0;
let calls = 0;
const handle = when(
() => {
checks++;
if (checks === 2) handle.clear();
return checks >= 4;
},
() => calls++,
);
t.after(() => handle.clear());

await setImmediate();
await setImmediate();
await setImmediate();

assert.equal(checks, 2);
assert.equal(calls, 0);
});

test("clear inside a truthy predicate suppresses its callback", async (t) => {
let checks = 0;
let calls = 0;
const handle = when(
() => {
checks++;
if (checks === 2) {
handle.clear();
return true;
}
return false;
},
() => calls++,
);
t.after(() => handle.clear());

await setImmediate();

assert.equal(calls, 0);
});

test("reset ignores a truthy result from the previous check", async (t) => {
let checks = 0;
let calls = 0;
const handle = when(
() => {
checks++;
if (checks === 2) {
handle.reset();
return true;
}
return false;
},
() => calls++,
);
t.after(() => handle.clear());

await setImmediate();

assert.equal(checks, 3);
assert.equal(calls, 0);
handle.setCondition(() => true);
await setImmediate();
assert.equal(calls, 1);
});

test("reset inside a false predicate leaves only one cancellable poll", async (t) => {
let checks = 0;
let calls = 0;
const handle = when(
() => {
checks++;
if (checks === 2) handle.reset();
return checks >= 4;
},
() => calls++,
);
t.after(() => handle.clear());

await setImmediate();
handle.clear();
await setImmediate();

assert.equal(checks, 3);
assert.equal(calls, 0);
});
94 changes: 42 additions & 52 deletions when.js
Original file line number Diff line number Diff line change
@@ -1,52 +1,42 @@
// the require('setImmediate') adds a setImmediate polyfill to the global
// scope. (this is for backwards and browser compatibility)
require('setimmediate');

function when(condition, code){
// set immediate to a blank function, I don't want to push the first
// check condition to a back of a queue
var immediate = setImmediate(function(){});

checkCondition(); //do a check straight away.


function checkCondition(){
if(condition()){
clear(); //there might be nothing to clear, but theres no harm calling it.
code(); //if the condition is true, run the code striaght away.

// in previous releases, I pushed the code() to the back of the io queue again with a setImmediate,
// but there is no point in doing that, making the program wait longer to execute something
// which might change the state to fire another when function.
} else {
immediate = setImmediate(checkCondition);
}
}

function clear(){
clearImmediate(immediate);
}

function reset(){
clear();
immediate = setImmediate(function(){});
checkCondition();
}

function setCondition(newCondition){
condition = newCondition;
}

function setCode(newCode){
code = newCode;
}

return {
'clear': clear,
'reset': reset,
'setCondition': setCondition,
'setCode': setCode
};
};

module.exports = exports = when;
require("setimmediate");

function when(condition, code) {
let immediate;
let generation = 0;

function checkCondition() {
const currentGeneration = generation;
const ready = condition();
if (currentGeneration !== generation) return;

if (ready) {
clear();
code();
} else {
immediate = setImmediate(checkCondition);
}
}

function clear() {
generation++;
clearImmediate(immediate);
}

function reset() {
clear();
checkCondition();
}

function setCondition(newCondition) {
condition = newCondition;
}

function setCode(newCode) {
code = newCode;
}

checkCondition();
return { clear, reset, setCondition, setCode };
}

module.exports = when;
Loading