Skip to content

Commit

Permalink
fix(scanner): workers not always terminated
Browse files Browse the repository at this point in the history
The computed property `shouldScan` in QrcodeStream is the source
of truth for the scanners state. Therefore each `keepScanning`
call receives a function enabling it to check `shouldScan`s value
outside of the components context. Since computed properties are
evaluated in an asynchronous manner, a running scanner might miss
point where `shouldScan` is actually `false`. When `keepScanning`
is called many times in a row, new web workers are spawned
endlessly without being terminated, causing a major memory leak.

Now fixed by putting the action to terminate scanners in the same
watcher where scanners are started.
  • Loading branch information
gruhn committed Dec 13, 2018
1 parent 506de1a commit cb8beec
Show file tree
Hide file tree
Showing 2 changed files with 12 additions and 4 deletions.
8 changes: 6 additions & 2 deletions src/components/QrcodeStream.vue
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ export default {
cameraInstance: null,
destroyed: false,
constraints: {},
stopScanning: () => {},
}
},
Expand Down Expand Up @@ -118,6 +119,8 @@ export default {
this.clearPauseFrame()
this.clearTrackingLayer()
this.startScanning()
} else {
this.stopScanning()
}
},
Expand Down Expand Up @@ -186,16 +189,17 @@ export default {
},
startScanning () {
// this.stopScanning()
const detectHandler = result => {
this.onDetect(
Promise.resolve({ source: 'stream', ...result })
)
}
keepScanning(this.cameraInstance, {
this.stopScanning = keepScanning(this.cameraInstance, {
detectHandler,
locateHandler: this.onLocate,
shouldContinue: () => this.shouldScan,
minDelay: this.scanInterval,
})
},
Expand Down
8 changes: 6 additions & 2 deletions src/misc/scanner.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ export function keepScanning (camera, options) {
const {
detectHandler,
locateHandler,
shouldContinue,
minDelay,
} = options

Expand All @@ -36,6 +35,7 @@ export function keepScanning (camera, options) {
// If worker can't process frames fast enough, memory will quickly full up.
// Make sure to process only one frame at a time.
let workerBusy = false
let shouldContinue = true

worker.onmessage = event => {
workerBusy = false
Expand All @@ -55,7 +55,7 @@ export function keepScanning (camera, options) {
}

const processFrame = timeNow => {
if (shouldContinue()) {
if (shouldContinue) {
window.requestAnimationFrame(processFrame)

if (timeNow - lastScanned >= minDelay) {
Expand All @@ -75,4 +75,8 @@ export function keepScanning (camera, options) {
}

processFrame()

return () => {
shouldContinue = false
}
}

0 comments on commit cb8beec

Please sign in to comment.