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!