这是 Deferred 的一个很好的用例吗?

Is this a good use case for a Deferred?

我经常听到有人将 Deferred 描述为 'anti-pattern'(例如 here)。 我试图了解我是否有使用延迟有意义的场景,也许你可以提供帮助。我在单页网络应用程序的页面上有一个 recaptcha。要执行某些操作,需要通过验证码测试。由于验证码在一段时间后过期,用户可能需要重做测试。但有时用户可能会在验证码过期之前触发这些操作之一,因此不应重做测试。下面是一些伪代码,以便更好地理解:

class App {
  constructor () {
    this.captchaPromise = new Deferred();
  }

  maybeDoIt () {
    this.captchaPromise.then(() => {
       this._doIt();
    })
  }

  _doIt () {
    alert('done');
  }

  _onCaptchaSuccess () {
    this.captchaPromise.resolve();
  }

  _onCaptchaExpire () {
    this.captchaPromise.reject();
    this.captchaPromise = new Deferred();
  }
}

const app = new App();

window._captchaOnload = function () {
  window.grecaptcha.render('js-captcha', {
    'sitekey': 'dsadaablsabllbalblablalblablablalbalbalblablabla31',
    'callback': app._onCaptchaSuccess.bind(app),
    'expired-callback': app._onCaptchaExpire.bind(app)
  });
};

您认为这是实现上述场景的好方法吗?

我也在努力寻找支持 es6 模块导入语法并且至少支持 IE9 及更高版本的 vanilla js 延迟实现或库,即使 IE8 也很棒(我不能使用 jQuery) .非常感谢任何帮助。

更新:

谢谢你的回答,最后我决定我根本不需要承诺。不过,承诺重新验证渲染是个好主意。我解决了以下问题:

  _doIt (data) {
    if (!this._captchaSolved) {
      this._dataToUseAfterCaptchaSuccess = data;
      return;
    }
    this._dataToUseAfterCaptchaSuccess = null;

    console.log('done', data);
  }

  _onCaptchaSuccess (captchaResponse) {
    this._captchaSolved = true;
    this._captchaResponse = captchaResponse;

    if (this._dataToUseAfterCaptchaSuccess) {
      this._doIt(this._dataToUseAfterCaptchaSuccess);
    }
  }

  _onCaptchaExpire () {
    this._captchaSolved = false;
  }

据我所知,没有必要使用 Deferred。

正如所写,它做了两件事,这两件事都可以更简单地实现:

  • 作为状态指示符:'pending' 实际上表示 'unexpired',而 'rejected' 表示 'expired'。可以改用简单的布尔值。
  • 作为调用 _doIt() 的一种方式:可以直接从 _onCaptchaSuccess 处理程序调用,甚至可以指定为 .render 的 'callback' 处理程序。

更现实的方法是承诺 window.grecaptcha.render(),例如:

window._captchaOnload = function () {
    new Promise(function(resolve, reject) {
        window.grecaptcha.render('js-captcha', {
            'sitekey': 'dsadaablsabllbalblablalblablablalbalbalblablabla31',
            'callback': resolve,
            'expired-callback': reject
        });
    })
    .then(app._doIt.bind(app), app.expire.bind(app));
};

app 需要相应地写,不涉及 Deferreds 或 promises。