javascript递归的实际应用场景

递归是各种书里经常讲到的东西,但是今天才在工作中遇到合适的使用场景,用过一次之后对他的理解也更具体了,在这里整理一下。

递归

递归的概念简单来说,就是在函数里边调用函数本身。
比如一个阶乘函数:

function factorial (n) {
    if(n === 1){
        return
    }
    return n * factorial(n-1)
}
factorial5

尾递归

但是像上边那样递归会保存很多个调用帧,比如上边的factorial(5),这个方法要执行5次,才能返回最终的计算表达式,这样每次都要保存这个方法,就容易造成栈溢出。为了解决这个问题,我们会使用尾递归:

function factorial (n, total=1) {
    if(n === 1){
        return total
    }
    return factorial(n-1, n * total)
}
factorial5

这样,每一次返回的就是一个新的函数,不带上一个函数的参数,也就不需要储存上一个函数了。只需要一个帧即可。

工作中的使用场景

回到正题,工作中其实不太会经常让你求个阶乘啥的。递归的使用场景也就比较少,但是今天让我遇到一个,就赶紧记下来:使用循环发送ajax请求
实际场景是这样的,我维护的table列表组建,做了一个表头筛选的功能。其中就需要获取筛选项,当有多个筛选项数组都需要从后台获取的时候,就需要循环数组发送ajax请求,但是由于ajax是异步的。多个请求就无法正常处理返回。
所以使用递归,在ajax的回调中重新调用他:

// data是配置对象的数据
// 通过data[currentIndex ],currentIndex++来循环
var data = [obj1,obj2,obj3]
var currentIndex = 0
var sendAjax = function () {
  // 结束递归的条件,不然就无限循环下去了。
  if(currentIndex >= data.length){
    return
  }
  // 获取ajax所需的参数
  var config = data[currentIndex],
    postMethod = config.postMethod || 'doGet',
    postData = config.postData || {},
    path = config.getOptsPath,
    $th = self.$thead.find('th[filter-name="' + config.filterName + '"]')
  // 发起请求
  Common[postMethod](path, postData, function (res) {
    // 回调中增加currentIndex
    currentIndex++
    // 处理请求数据
    var filterDataParseMode = config.filterDataParseMode
    var data = self.filterDataParse(res, filterDataParseMode)
    var content = self.theadFilterRender({
      data: config,
      options: data
    })
    $th = self.$thead.find('th[filter-name="' + config.filterName + '"]'),
    $th.html(content);
    $th.find('ul').find('li:first').addClass('gridList-filter-active');
    // 请求数据处理结束后递归,再一次请求
    sendAjax()
  }, function(rej){
    // 失败也要继续递归,这样才不影响其他的请求。
    currentIndex++
    sendAjax()
  })
}
sendAjax()

你可能感兴趣的:(实践思考)