2017-10-14 74 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

相关问题