When subscribing to events using methods like atom.workspace.onDidAddTextEditor
, it is important remove the event listeners when you no longer need your callback to be called (e.g. when your package is deactivated). To do this, store the returned Disposable
, and call .dispose
on it:
module.exports = {
activate () {
this.editorSubscription = atom.workspace.onDidAddTextEditor(editor => {
console.log('Added a text editor!', editor)
})
},
deactivate () {
this.editorSubscription.dispose()
}
}
You will often need to use multiple event listeners in your package. You can easily remove multiple listeners at a time using the CompositeDisposable
class:
const {CompositeDisposable} = require('atom')
module.exports = {
activate () {
this.subscriptions = new CompositeDisposable()
this.subscriptions.add(atom.workspace.onDidAddPane(pane => {
console.log('Added a pane!', pane)
}))
this.subscriptions.add(atom.workspace.onDidDestroyPane(pane => {
console.log('Destroyed a pane!', pane)
}))
},
deactivate () {
this.subscriptions.dispose()
}
}
The event listeners in the previous two examples were registered on atom.workspace
, an object that exists for the life of the application. Oftentimes though, you'll need to register event listeners on objects like TextEditors
, which are created and destroyed frequently. This can give rise to another type of memory leak: Disposables
themselves can retain objects like TextEditors
unnecessarily:
const {CompositeDisposable} = require('atom')
module.exports = {
activate () {
this.subscriptions = new CompositeDisposable()
this.subscriptions.add(atom.workspace.onDidAddTextEditor(editor => {
// Memory leak - this `Disposable` retains `editor` until the package is
// deactivated, even though `editor` may be destroyed long before then!
const editorSubscription = editor.onDidStopChanging(() => {
console.log('Editor changed', editor)
})
this.subscriptions.add(editorSubscription)
}))
},
deactivate () {
this.subscriptions.dispose()
}
}
To avoid this type of leak, you need to release Disposables
that reference the editor when the editor is destroyed. You can do this using the editor's onDidDestroy
method:
const {CompositeDisposable} = require('atom')
module.exports = {
activate () {
this.subscriptions = new CompositeDisposable()
this.subscriptions.add(atom.workspace.onDidAddTextEditor(editor => {
const editorSubscriptions = new CompositeDisposable()
editorSubscriptions.add(editor.onDidStopChanging(() => {
console.log('Editor changed', editor)
}))
editorSubscriptions.add(editor.onDidDestroy(() => {
editorSubscriptions.dispose()
this.subscriptions.remove(editorSubscriptions)
}))
this.subscriptions.add(editorSubscriptions)
}))
},
deactivate () {
this.subscriptions.dispose()
}
}
All objects in Atom that have event APIs and finite lifetimes should have an onDidDestroy
method that works the same way. Examples:
Thanks, great help!