2017-10-14 66 views
0

我有多個Javascript函數,每個都執行一些DOM操作,然後運行一個ajax請求。我希望能夠運行第一個函數,該函數操縱DOM,然後觸發它的ajax請求,然後,當ajax請求完成時,如果ajax請求返回true,或者要停止執行其他的函數,我想運行第二個函數的功能和做一些其他的DOM操作(如顯示錯誤消息)。如何順序運行多個函數,並在其中任何一個失敗時停止所有函數?

我希望這些函數能夠依次運行,一個接一個地運行,並且只有在它們沒有一個從它們的ajax請求返回false時才繼續運行。如果它們中沒有一個返回false,那麼它們都應該運行,最終我會在我的「始終」回調中進行一些操作。

我該如何做到這一點?

我的第一個想法是使用承諾,以保持代碼更清潔,但經過幾個小時的閱讀,我無法得到如何使這項工作。

下面是我當前的代碼,這就是我得到了我的控制檯,當它執行:

inside test1 
inside test2 
inside test3 
fail 
[arguments variable from fail method] 
always 
[arguments variable from always method] 

這是我想在我的控制檯得到(注意失蹤「內TEST3」字符串) :

inside test1 
inside test2 
fail 
[arguments variable from fail method] 
always 
[arguments variable from always method] 

下面的代碼:

(function($) { 
    var tasks = { 
     init: function() { 
      $.when(
       this.test1(), 
       this.test2(), 
       this.test3() 
      ).done(function() { 
       console.log('done'); 
       console.log(arguments); 
      }) 
      .fail(function() { 
       console.log('fail'); 
       console.log(arguments); 
      }) 
      .always(function() { 
       console.log('always'); 
       console.log(arguments); 
      }); 
     }, 

     test1: function() { 
      console.log('inside test1'); 
      return $.getJSON('https://baconipsum.com/api/?type=meat-and-filler'); 
     }, 

     test2: function() { 
      console.log('inside test2'); 
      // note the misspelled "typ" arg to make it fail and stop execution of test3() 
      return $.getJSON('https://baconipsum.com/api/?typ=meat-and-filler'); 
     }, 

     test3: function() { 
      console.log('inside test3'); 
      return $.getJSON('https://baconipsum.com/api/?type=meat-and-filler'); 
     } 
    }; 

    tasks.init(); 
})(jQuery) 

任何想法?

回答

1

使用承諾不使代碼更乾淨

注:無極/ A +答應。後來和.catch回調永遠只能接受一個參數,所以不需要找在arguments,只需用一個參數

此代碼(ES2015 +)展示瞭如何輕鬆

let p = Promise.resolve(); 
Promise.all([this.test1, this.test2, this.test3].map(fn => p = p.then(fn()))).then(allResults => 

可替代地,使用array.reduce

[this.fn1, this.fn2, this.fn3].reduce((promise, fn) => promise.then(results => fn().then(result => results.concat(result))), Promise.resolve([])).then(allResults => 

在兩種情況下,allResults是(解析)的結果從testN函數數組

它創建了一個(解析)承諾「開始」的鏈的承諾

Array#map鏈將每個函數(this.test1等)在之前的結果中執行。每個this.testn承諾的結果是在一個新的數組中,如果任何testN的失敗,未來不會被執行

var tasks = { 
    init() { 
     let p = Promise.resolve(); 
     Promise.all([this.test1, this.test2, this.test3].map(fn => p = p.then(fn()))) 
     .then(results => { 
      console.log('done'); 
      console.log(results); 
      return results; // pass results to next .then 
     }).catch(reason => { 
      console.log('fail'); 
      console.log(reason); 
      return reason; // because I return rather than throw (or return a Promise.reject), 
      //the next .then can will get `reason` in it's argument 
     }).then(result => { 
      console.log('always'); 
      console.log(result); 
     }); 
    }, 
    test1() { 
     return $.getJSON('https://baconipsum.com/api/?type=meat-and-filler'); 
    }, 
    test2() { 
     return $.getJSON('https://baconipsum.com/api/?typ=meat-and-filler'); 
    }, 
    test3() { 
     return $.getJSON('https://baconipsum.com/api/?type=meat-and-filler').then(result => { 
      if(someCondition) { 
       throw new Error("sum ting wong"); 
       // or 
       return Promise.reject(new Error("sum ting wong")); 
      } 
      return result; 
     }); 
    } 
}; 
tasks.init(); 

中的問題,你可以將代碼爲Promise.all

的參數返回簡化進一步

var tasks = { 
    init() { 
     let p = Promise.resolve(); 
     const urls = [ 
      'https://baconipsum.com/api/?type=meat-and-filler', 
      'https://baconipsum.com/api/?typ=meat-and-filler', 
      'https://baconipsum.com/api/?type=meat-and-filler' 
     ]; 
     Promise.all(urls.map(url => p = p.then(() => $.getJSON(url)))) 
     .then(results => { 
      console.log('done'); 
      console.log(results); 
      return results; // pass results to next .then 
     }).catch(reason => { 
      console.log('fail'); 
      console.log(reason); 
      return reason; // because I return rather than throw (or return a Promise.reject), 
      //the next .then can will get `reason` in it's argument 
     }).then(result => { 
      console.log('always'); 
      console.log(result); 
     }); 
    } 
}; 
tasks.init(); 
+0

This看起來像我之後...雖然我不確定胖箭頭函數是否支持與常規匿名函數相同的方式?我會嘗試一下,但這看起來非常棒!謝謝你,@Jaromanda X – andrux

+0

'=>'使代碼更加簡潔,而且''this'的更少麻煩:p你總是可以傳遞上面的代碼 –

+0

我把你的代碼轉換成了「常規」的JS,它運行起來,記錄我在控制檯期待的內容:https://gist.github.com/andruxnet/11a0c2baa45e870fc449bac02cb66bf5 – andrux

0

你並不需要使用的承諾 - 也許你知道這一點,但你可以保持通話在prevoius一個成功的塊中的下一個Ajax請求,就像這樣:

(function($) { 
    var tasks = { 
     init: function() { 
        $.post(url_1, data_1, function(data,status){ 
      if(status == 'success') 
      { 
       $.post(url_2, data_2, function(data,status){ 
        if(status == 'success') 
        { 
         // ... and the next Ajax request goes here, etc. 
        } 
        else { 
         // show error message if 2nd Ajax request fails 
        } 
       } 
      else { 
       // show error message if 1st Ajax request failes 
      } 
     }); 
    });  
     } 

    tasks.init(); 
})(jQuery) 
+0

歡迎厄運或回調地獄的金字塔 - 想象一下,即使只是10網址:p –

+0

其實在問題的代碼比我居然有短,真正的代碼有大約8 Ajax請求,和它可以添加更多 – andrux

1

我不像熟悉jQuery的承諾。

但這應該工作

(function ($) { 
    var tasks = { 
     init: function() { 
      this.test1().done(this.test2).done(this.test3) 
       .done(function() { 
        console.log('done'); 
        console.log(arguments); 
       }) 
       .fail(function() { 
        console.log('fail'); 
        console.log(arguments); 
       }) 
       .always(function() { 
        console.log('always'); 
        console.log(arguments); 
       }); 
     }, 

     test1: function() { 
      console.log('inside test1'); 
      return $.getJSON('https://baconipsum.com/api/?type=meat-and-filler'); 
     }, 

     test2: function() { 
      console.log('inside test2'); 
      // note the misspelled "typ" arg to make it fail and stop execution of test3() 
      return $.getJSON('https://baconipsum.com/api/?typ=meat-and-filler'); 
     }, 

     test3: function() { 
      console.log('inside test3'); 
      return $.getJSON('https://baconipsum.com/api/?type=meat-and-filler'); 
     } 
    }; 

    tasks.init(); 
})(jQuery) 
+0

謝謝,我想它可以工作,我會用這個,如果我不認爲有可能添加更多的Ajax請求,所以我想代碼很容易擴展..這個解決方案會變得有點混亂與其他幾個回調 – andrux

+0

我不確定你的意思,這連鎖你一起創造的3個承諾,這是你問的。我假設在你的實際代碼中,除了查找json數據之外,你還在做更多的內部函數test1,test2,test3。 你在找什麼其他的改變? –

+0

我的意思是,它的工作原理(或者至少它應該可以正常工作),但我希望能夠輕鬆地添加更多的功能,鏈接test1,test2,...,test20可能看起來有點混亂,難以維護(如果我想評論其中的一部分,該怎麼辦?)這是一個很好的解決方案,但是這個代碼可能會在未來由其他開發人員維護,並且我想盡可能簡化他們,如果我不在身邊 – andrux

相關問題