LoginSignup
2
5

More than 5 years have passed since last update.

jQuery.Deferred で可変個の Deferred 関数を扱う際の Tips

Last updated at Posted at 2017-04-28

はじめまして。「ぱいな」と申します。

私は自称ネットワークエンジニアなのですが,最近 Web まわりもちょっと勉強していて,jQuery を使ってます。この投稿は jQuery.Deferred についてです。タイトルに "Tips" と書きましたが,本音は「これもっと良い方法あるんじゃね?」というところなので,もし良い方法があったらコメントくださいまし。

Deferred 関数の逐次処理

さて,非同期処理の強い味方,jQuery.Deferred ですが,可変個の Deferred 関数を扱うケースがあると思います。$.when.apply() を使って配列として渡してあげれば,一気に処理してくれますね。

example01.js
// jQuery.Deferred を使った何か非同期処理をする関数
function deferredFunc(mesg) {
    var dfd = $.Deferred();

    setTimeout(function () { // 0~5秒のランダムな時間の後に引数をログ出力する
        console.log(mesg);
        dfd.resolve();
    }, Math.random() * 5000);

    return dfd.promise();
}

// これを可変個とする
var messages = ["poi", "poe", "pui"];

// 可変個の配列を map して要素を deferredFunc に渡す
var deferreds = messages.map(function (mesg) {
    return deferredFunc(mesg);
});

// 全ての deferredFunc が resolve したら "Done!" とログ出力する
$.when.apply($, deferreds).done(function () {
    console.log("Done!");
});

しかし,Deferred 関数を逐次処理したいケースも,希かもしれませんがありうるでしょう。(「jQuery.Deferred 使わないで普通に書けば?」というツッコミもありそうですが,Deferred 関数をいじれない時などです。)

Deferred 関数の個数が決まっていれば then() をチェインしていけば良いです。今回の例では無名関数で包む必要があるのでちょっと面倒ですが,こんな感じに。

example02.js
deferredFunc("one").then(function () {
    return deferredFunc("two");
}).then(function () {
    return deferredFunc("three");
});

"one", "two", "three" が順番にログ出力されます。

では Deferred 関数の個数,というか Deferred 関数で処理したい配列等の個数が可変個だったら。これしか思いつかなかったのですが reduce() でチェインしてみました。

example03.js
var messages = ["one", "two", "three"];

var deferreds = messages.map(function (mesg) { // ここではまだ実行したくないので,無名関数でくるむ
    return function () {
        return deferredFunc(mesg);
    };
});

deferreds.reduce(function (prev, curr) {
    return prev.then(function () {
        return curr();
    });
}, $.Deferred().resolve());

無名関数の嵐! でも,これで "one", "two", "three" が順番にログ出力されます。

もっと良い方法を募集中ー。

可変個の $.when.apply().done() の返値を処理する

可変個の Deferred 関数の返値(正確には resolve() の引数)を処理したいときもちょっと悩みました。

例えば,Deferred 関数を次のように変えてみます。

example04-01.js
function deferredFunc(mesg) {
    var dfd = $.Deferred();

    setTimeout(function () { // 0~5秒のランダムな時間の後に引数を resolve() する
        dfd.resolve(mesg);
    }, Math.random() * 5000);

    return dfd.promise();
}

前章の deferredFunc() と異なる点は,引数を関数内で console.log() するのではなく,resolve() する点です。可変個の deferredFunc()$.when.apply().done() にかけたとき,返値を処理するにはどうするか悩みました。これも良い方法を募集中なのですが,こんな感じで一応解決。

example04-02.js
var messages = ["one", "two", "three"];

var deferreds = messages.map(function (mesg) {
    return deferredFunc(mesg);
});

$.when.apply($, deferreds).done(function () {
    for(var i = 0; i < arguments.length; i++) { // arguments は forEach() 使えない
        console.log(arguments[i]);
    }
    console.log("Done");
});

JavaScript において,関数の引数は仮引数だけではなく arguments でも受けられます。こうすれば,全ての deferredFunc()resolve() した後,"one", "two", "three" が一度にログ出力されます。

2
5
0

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
2
5