LoginSignup
9
10

More than 5 years have passed since last update.

非同期の再試行をシンプルに。

Last updated at Posted at 2015-09-11

プロミス処理のラッパーをつくる」という記事でつくった Promise ラッパーで非同期処理が捗っているので進捗報告。

(追記) ここで書いた関数は Promise のアンチパターンである "explicit construction" になってて、それで Promise チェーンが機能してなかった。恥ずかしながら、修正しました。

n * 1000 ミリ秒間隔で n 回再試行

Promise 化した処理をタイトル通り繰り返し処理したい時に使える関数:

var count = function (done, times, interval) {
  return done()
  .then(function (dat) {
    return dat;
  }, function (err) {
    if (1 >= times) return err;
    return sleep(interval)  // 下記で解説
    .then(function () {
      return count(done, times - 1, interval);
    });
  });
};

// ※ 当初 `promisify` 高階関数でラップしてたけど、不要だしアンチパターンでした。お恥ずかしい。

使用例

// Underscore.js と jQuery が必要

var ajaxOpts = {
  data: { foo: 'bar' },
  method: 'GET'
};
count(_.bind($.ajax, undefined, '//example.com/no/existence', ajaxOpts), 3, 1000)
.then(function (resp) {
  // 1 秒間隔で最大 3 回再試行してレスポンスが得られた場合
}, function (jqXHR) {
  // 1 秒間隔で最大 3 回再試行してエラーだった場合
});

上記例は複雑なパターンだけど、$.ajax が Promise を返す関数なので、それを count に渡すと、1 秒間隔で最大 3 回再試行してくれる。count は高階関数じゃないので、$.ajax の引数が受けられない。なので、_.bind$.ajax にも然るべき引数を与えている。

依存関数

上記関数内で使用している Promise タイマー関数はこちら:

// 「プロミス処理のラッパーをつくる」でつくった `promisify` 関数が必要

var sleep = promisify(function (resolve, reject, millisec) {
  if (!millisec) millisec = 80;
  var timeoutId = setTimeout(function () {
    clearTimeout(timeoutId);
    resolve(millisec);
  }, millisec);
});

n * 1000 ミリ秒間に可能な限り再試行

こっちは制限時間内に可能な限り繰り返し処理したい時に使える関数:

// Underscore.js が必要

var tick = function (done, duration, start) {
  if (!_.isNumber(start)) start = +(new Date());
  return done()
  .then(function (dat) {
    return dat;
  }, function (err) {
    var stop = +(new Date());
    if (duration > stop - start) return tick(done, duration, start);
    return err;
  });
};

// ※ 当初 `promisify` 高階関数でラップしてたけど、不要だしアンチパターンでした。お恥ずかしい。

使用例

// Underscore.js と jQuery が必要

var ajaxOpts = {
  data: { foo: 'bar' },
  method: 'GET'
};
tick(_.bind($.ajax, undefined, '//example.com/no/existence', ajaxOpts), 3000)
.then(function (resp) {
  // 3 秒間に可能な限り再試行してレスポンスが得られた場合
}, function (jqXHR) {
  // 3 秒間に可能な限り再試行してエラーだった場合
});

これは前述のパターンと同じなので省略。

これ捗りそう...!

謝辞

9
10
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
10