2

I am trying to write a Nylas N1 plugin, and so I started by just modifying the built-in spellcheck (here https://github.com/nylas/N1/blob/master/internal_packages/composer-spellcheck/lib/spellcheck-composer-extension.es6). I imported the underscore library, and tried to throttle the _wrapMisspelledWords function:

import _ from 'underscore';
...
export default class SpellcheckComposerExtension extends ComposerExtension {
  ...
  static onContentChanged({editor}) {
    SpellcheckComposerExtension.update(editor);
  }

  static update = (editor) => {
    SpellcheckComposerExtension._unwrapWords(editor);
    SpellcheckComposerExtension._wrapMisspelledWords(editor);
  }

  static _wrapMisspelledWords = _.throttle((editor) => {
    console.log('wrap mispelled words');
    ...
    ...
  }, 2000)
  ...
}

It appears to throttle correctly at first, and then seems to get stuck in some loop, constantly repeating output from previous changes. I have read through another thread (Perform debounce in React.js) but can't figure out why this behavior is happening.

EDIT:

It might make more sense to throttle the update function, but I see the same issue.

EDIT:

OK instead of throttling or debouncing, I decided to wrap the update function in setTimeout(..., 0) in order to debug, and still shows this same issue.

The conditions for entering an infinite loop seem to be:

  • there is at least one spelling mistake (so that unwrap and wrap say that they've modified the content)
  • the update function is added to the event queue instead of firing immediately (using setTimeout, throttle or debounce)

The contenteditable component (https://github.com/nylas/N1/blob/1b4739335f4452faa720914309c5e6a593db531d/src/components/contenteditable/contenteditable.cjsx#L302-L333) has a mutation observer that stops listening while the extensions run, and I think when I add my update to the event queue, it starts listening for mutations before the update can run, causing another mutation to be observed, entering the infinite loop.

Any solutions, or tips?

Community
  • 1
  • 1
user20061
  • 444
  • 6
  • 12
  • Hey, have you visited this question since your updates? Have you stumbled on a solution that hasn't been mentioned? It would be helpful to the education other users if you either post your own solution or accept a working solution to your question. – taystack Oct 29 '18 at 16:08

1 Answers1

2

I know this is a bit late here, but I've done this same thing before.

class Thing {
  static someFn() {
    // whatever you do
  }

  static heavyAJAX() {
    // some heavy ajax
  }
}

Thing.someFn = _.throttle(Thing.someFn, 2000);
Thing.heavyAJAX = _.debounce(Thing.heavyAJAX, 1000);

This pattern has worked for me with throttle and debounce. You can also use the same approach with instance methods. If our methods weren't static, you would just use Thing.prototype:

Thing.prototype.someFn = _.throttle(Thing.prototype.someFn, 2000);
Thing.prototype.heavyAJAX = _.debounce(Thing.prototype.heavyAJAX, 1000);

If you were to do this with instance methods, I would suggest a composure approach in the constructor:

class Thing {
  constructor() {
    this.someFn = _.throttle(this.someFn, 2000);
  }

  someFn() {
    // your things...
  }
}
taystack
  • 2,004
  • 18
  • 17