Skip to content

Instantly share code, notes, and snippets.

@hasegawayosuke
Created February 23, 2022 08:27
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hasegawayosuke/d7a45542a092901edb059c8cbcb96c7a to your computer and use it in GitHub Desktop.
Save hasegawayosuke/d7a45542a092901edb059c8cbcb96c7a to your computer and use it in GitHub Desktop.
Asynchronous RegExp for node.js with termination
const { Worker, isMainThread, workerData, parentPort } = require('worker_threads')
if (isMainThread) {
class AsyncRex {
constructor (pattern, flags) {
if (pattern instanceof RegExp) {
this.source = pattern.source
this.flags = pattern.flags
} else if (typeof pattern === 'string') {
this.source = pattern
this.flags = flags
} else {
throw new TypeError('The "pattern" argument must be of type string or an instance of RegExp.')
}
}
#invoke (method, text, ms) {
const flags = this.flags
const pattern = this.source
let timer
const worker = new Worker(__filename, { workerData: { pattern, flags, method, text } } )
const sleep = (ms) => {
return new Promise((resolve, reject) => {
timer = setTimeout(() => {
try {
worker.terminate()
} catch (e) {
console.error('Couldn\'t terminate worker thread.', e)
}
reject('timeout')
}, ms)
})
}
const asyncRexInvoke = () => {
return new Promise((resolve, reject) => {
worker.on('message', (result) => {
if (timer !== undefined) {
clearTimeout(timer)
}
resolve(result)
})
worker.on('error', reject)
worker.on('exit', reject)
})
}
return Promise.race([
asyncRexInvoke(),
sleep(ms)
])
}
test (text, ms = 100) {
return this.#invoke('test', text, ms)
}
exec (text, ms = 100) {
return this.#invoke('exec', text, ms)
}
}
module.exports = {AsyncRex}
} else {
const { pattern, flag, method, text } = workerData
if (method === 'test' || method === 'exec') {
const re = new RegExp(pattern, flag)
const result = re[method](text)
parentPort.postMessage(result)
} else {
parentPort.postMessage(undefined)
}
}
const { AsyncRex } = require('./async_rex')
const main = () => {
// new AsyncRex('([\\da-f]+)', 'i')
// new AsyncRex(/([\da-f]+)/i)
const rex = new AsyncRex(/\s+$/)
const s = ' '.repeat(65536) + 'a'
console.time()
rex.test(s, 100).then((result) => {
console.timeEnd()
console.log(result)
}).catch(err => {
console.timeEnd()
console.error(err)
})
}
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment