18759
アンケートを作っています。  
`<input type="button">`が複数あり、ボタンを押すとAjaxで親のフォームアクションから非同期通信を行います。

この時ボタンがA,B,C,Dあったとして、ABCは普通にAjax通信します。DだけABC同様に通信した後、さらに選択ボタンD1,D2,D3が現れ、それらもAjax通信する際、

```

    $.ajax({
        type: 'post',
        url: 'europost.jp/question.php',
        data: formdata
    }).done(function(data, status) {
        if(status == "success") {
            if($(this).hasClass('D') {
                    $.ajax({~省略
            }
            return false;
        }
    
```

このようにAjax文の中にさらにAjax文をネストするのは嫌です。  
条件として、Dをクリックしても必ず最初に一度通信は行われるものです。  
できれば下記みたいなAjax関数にするのも嫌です。

```

    function Ajax(){
        if(D){
            Ajax();
        }
    }
    
```
CC BY-SA 3.0
2015-11-12T03:46:13.253
18711
2017-06-19T05:08:41.447
2017-06-19T05:08:41.447
5793
7973
question
javascript ajax
Ajaxでsuccessした時に、さらにAjax通信したいです
非同期処理をしている以上コールバックを待たなければいけないので  
関数がネストするのは避けられないと思います。  
同じAjax通信を処理するなら通信部だけ

```

    /**
     * @param options  Object   : for send data
     * @param callback Function : for callback function
     **/
    function connection(options, callback){
      $.ajax({
        type: 'post',
        url: 'europost.jp/question.php',
        data: options,
        success: callback
      });
    }
    
```

とか外に出してやるくらいしかできないのでは？  
流れが決まっているなら

```

    function flow1(){
      connection({},flow2);
    }
    
    function flow2(data, status){
      if("success"==status){ connection({},flow3);}
    }
    
    function flow3(data, status){
      //...
    }
    
```

のようにも出来ますが、結局ネストしてるだけなんで何とも……
CC BY-SA 3.0
2015-11-12T06:20:26.740
18720
2015-11-12T06:20:26.740
7676
18711
answer
A,B,Cのボタンを押した時はbuttonTask, Dのボタンを押した時はbuttonTask, buttonDTaskを実行します。

GET/POST、フォーム/JSONなど細かな違いはありますが、本質的な部分はご要望を満たしているのではないかと思います。

```

    <html>
      <head>
        <script src="https://code.jquery.com/jquery-2.1.4.js"></script>
        <script>
          $(function() {
            $.extend({
              sequence: function() {
                var tasks = Array.prototype.slice.call(arguments),
                    d = $.Deferred(),
                    p = d.promise();
                $.each(tasks, function(i, task) {
                  p = p.pipe(task);
                });
                d.resolve();
                return p;
              }
            });
    
            var buttonTask = function() {
              return $.getJSON('http://ip.jsontest.com').pipe(
                function(res) { return res; },
                function() { return 'button task failed!'; }
              );
            };
    
            var buttonDTask = function() {
              return $.getJSON('http://date.jsontest.com').pipe(
                function(res) { return res; },
                function() { return 'button D task failed!'; }
              );
            };
    
            $('button').on('click', function() {
              var s;
              if ($(this).hasClass('D')) {
                s = $.sequence(buttonTask, buttonDTask);
              } else {
                s = $.sequence(buttonTask);
              }
              s.fail(function(r) {
                console.log('fail: ', r);
              }).always(function(r) {
                console.log('always: ', r);
              });
            });
          });
        </script>
      </head>
      <body>
        <button>A</button>
        <button>B</button>
        <button>C</button>
        <button class="D">D</button>
      </body>
    </html>
    
```
CC BY-SA 3.0
2015-11-12T19:18:07.323
18759
2015-11-12T19:18:07.323
7837
18711
answer
非同期処理で頻発するそのようなコールバックのネストを解消するためには、[ジェネレータ](https://developer.mozilla.org/ja/docs/Web/JavaScript/Guide/Iterators_and_Generators)を使います。コード例としては以下のようになります。

```

    co(function*() {
      
      var data = yield $.ajax({
        type: 'post',
        url: 'europost.jp/question.php',
        data: formdata
      }).promise();
    
      if ($(this).hasClass('D')) {
        var result = yield $.ajax({ ... }).promise();
    
        ...
        
        return false;
      }
    
    });
```

```

    <script src="https://cdnjs.cloudflare.com/ajax/libs/co/4.1.0/index.js"></script>
```

なお、PromiseやDeferredでコールバックのネストが避けられるという主張がされることがありますが、それは関数を分割してネストを分解しているだけで、今度は一箇所に本来まとまっているべきコードが分散するという別の問題を持ち込むことになり、根本的な問題の解決にはなりません。よく勘違いされますが、Promiseの目的は非同期処理の抽象化であって、コールバック地獄の解消ではありません。
CC BY-SA 3.0
2015-11-16T14:38:42.540
18909
2015-11-16T19:04:56.917
2015-11-16T19:04:56.917
10330
10330
18711
answer