Skip to content

Instantly share code, notes, and snippets.

@bramblex
Created May 30, 2020 10:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bramblex/77a873af818d9514075e1622d6d48796 to your computer and use it in GitHub Desktop.
Save bramblex/77a873af818d9514075e1622d6d48796 to your computer and use it in GitHub Desktop.
const acorn = require("acorn");
const astring = require("astring");
const estraverse = require("estraverse");
function withCancel(func) {
const signalName = "__$isCancel__";
const shouldCancelName = "__$shouldCancel__";
function transform(node) {
return estraverse.replace(node, {
enter(node) {
if (/function/i.test(node.type)) {
return estraverse.VisitorOption.Skip;
}
return node;
},
leave(node) {
if (node.type === "AwaitExpression") {
return {
type: "CallExpression",
callee: {
type: "Identifier",
name: shouldCancelName,
},
arguments: [node],
};
}
return node;
},
});
}
const ast = acorn.parse(func.toString(), {});
ast.body[0].expression.body = transform(ast.body[0].expression.body);
const funcCode = astring.generate(ast).replace(/;\s*$/, "");
return `((function () {
var ${signalName} = false;
function ${shouldCancelName}(value) {
if (${signalName}) throw new Error('Cancel');
return value;
};
return [${funcCode}, function (){ ${signalName} = true }];
})())`;
}
function delay(t) {
return new Promise((resolve) => setTimeout(resolve, t));
}
async function __main__() {
const [a, cancelA] = eval(
withCancel(async () => {
for (let i = 0; i < 10; i++) {
await delay(1e3);
console.log(i);
}
})
);
try {
setTimeout(cancelA, 4e3);
await a();
} catch (error) {
if (error.message === "Cancel") {
console.log(error.message);
}
}
}
__main__();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment