22687
jQueryのDeferredを使う下記コードを作成しましたが、400エラーの時にfailが呼ばれると思いましたが、consoleに`GET
http://localhost:3000/api/favorite?id=100 400 (Bad
Request)`とでて処理が実行されません。200,201の時はdoneが実行されます。

コード

```

    $(function(){
        $(document).on('click', '#add-fav', function(){
            var id = $(this).data("id");
            addFav(id)
                .done(
                    function(data){
                        Materialize.toast(data.name+'を登録しました', 3000);
                    })
                .fail(
                    function(err){
                        Materialize.toast(err.reason, 3000);
                    }
                );
        });
    
        $(document).on('click', '#del-fav', function(){
            var id = $(this).data("id");
            delFav(id)
                .done(
                    function(){
                        Materialize.toast("削除しました。", 3000);
                    })
                .fail(
                    function(err){
                        Materialize.toast(err.reason, 3000);
                    }
                );
        });
    });
    
    // お気に入りを追加する。
    function addFav(id){
        var defer = $.Deferred();
        $.ajax({
            url: "/api/favorite",
            type: "GET",
            data: {
                id: id
            },
            dataType: "json",
            success: defer.resolve,
            error: defer.reject
        });
        return defer.promise();
    }
    
    // お気に入りを削除する。
    function delFav(id){
        var defer = $.Deferred();
        $.ajax({
            url: "/api/favorite",
            type: "DELETE",
            data: {
                id: id
            },
            success: defer.resolve,
            error: defer.reject
        });
        return defer.promise();
    }
    
```

エラー時にfailが呼ばれるようにするにはどのようにすればいいのでしょうか。
CC BY-SA 3.0
2016-02-29T15:22:10.940
22673
2016-03-01T06:30:03.893
7232
question
javascript jquery
jQuery deferredでfailが呼ばれない
`fail()` に渡したコールバック関数は正しく呼び出されていますが、あなたが期待したような引数は渡されていないため、正しく動作していません。

`deferred.reject()` にn個の引数を渡した場合、同じように `promise.fail()`
のコールバック関数もn個の引数で呼び出されます。今回 [`$.ajax()`](https://api.jquery.com/jQuery.ajax/)
はエラーハンドラに指定した `reject()` を `(jqXHR, textStatus, errorThrown)`
という3つの引数で呼び出したため、同じように `fail()` のコールバック関数も `(jqXHR, textStatus, errorThrown)`
と3つの引数で呼び出されます。

コールバック関数は呼び出されたものの、第一引数である `jqXHR` に `reason` というプロパティは存在しないため `undefined`
となり、期待したように通知が行われなかったのでしょう。

ちなみにjQuery1.5以降 [`$.ajax()`
はPromise互換のオブジェクトを返すので](https://api.jquery.com/jQuery.ajax/#jqXHR)、直接
`$.ajax(...).fail(...)` とできますが、この場合も前述のように3つの引数という形で呼び出されます。

```

    $.ajax({url: 'http://example.com/undefined'})
      .fail(function(jqXHR, textStatus, errorThrown) {
        alert("jqXHR: " + jqXHR + ", textStatus: " + textStatus + ", errorThrown:" + errorThrown);
      });
```

```

    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
```

なお、resolve/reject時に複数の引数を渡せるのはjQueryのDeferredに限った話で、Promise/A+やES2015のPromiseには一つの引数しか渡せません。
CC BY-SA 3.0
2016-03-01T06:30:03.893
22687
2016-03-01T06:30:03.893
8000
22673
answer