使用递归promise,Javascript附加到数组

时间:2017-10-28 22:57:28

标签: javascript arrays recursion promise

我正在尝试编译我从多个API调用中获取的数据列表,但是在构建数组并陷入无限递归方面存在问题。

调用递归函数的函数:

jsonToCsv () {
  this.exportCSV().then(data => {
    console.log('From jsonToCSV', data)
  })
}

递归功能

exportCSV (uidList = this.checkboxList.slice(), offset = 0) {
  // Get query, build request
  let request = {
    id: 'export',
    query: this.currentQuery.query,
    sort: this.currentQuery.sort,
    limit: 100, // how much data is returned
    offset: offset // pagination value
  }

  return new Promise((resolve, reject) => {

    // using Vuex to fetch data, returns an array of objects.
    this.$store.dispatch('show/fetchQuery', request).then(data => {
      let headerList = this.shownHeaders // an array of column id's & thier 'nice names'
      let output = []
      let row, uid, header

      // match the id's to the Data from the API call
      for (uid = 0; uid < uidList.length; uid++) {
        for (row = 0; row < data.length; row++) {
          if (data[row].uid === uidList[uid]) {
            let rowData = {}
            uidList.splice(uid, 1) // found this id so remove from list

            // take data from query call that we want, make objects, push them to array
            for (header = 0; header < headerList.length; header++) {
              let niceName = headerList[header].niceName
              let id = headerList[header].id
              rowData[niceName] = data[row][id]
            }
            output.push(rowData)
          }
        }
      }

      // Basecase
      if (uidList.length === 0) {
        resolve(output)
        return
      }

      offset += 100 // get next 100 results from query
      // run next recursive call
      this.exportCSV(uidList, offset).then(newData => {
        output.push(newData)
        resolve(newData)
      })
    })
  })

我相信我正确地处理了basecase,但是,如果必须多次调用查询,意味着2级递归,则只打印最新的递归调用返回值。数组输出被覆盖..如果不满足basecase,如何处理数据解析?

2 个答案:

答案 0 :(得分:0)

var exportCSV = (uidList = this.checkboxList.slice(1), offset = 0) => {
       return new Promise(function(resolveFinal){
                   var rec = (uidListTemp = uidList, offsetTemp = offset, output = [])=>{
                  let request = {
                    id: 'export',
                    query: this.currentQuery.query,
                    sort: this.currentQuery.sort,
                    limit: 100, // how much data is returned
                    offset: offset // pagination value
                  }

                  return new Promise((resolve, reject) => {

                    // using Vuex to fetch data, returns an array of objects.
                    this.$store.dispatch('show/fetchQuery', request).then(data => {
                      let headerList = this.shownHeaders // an array of column id's & thier 'nice names'
                      let row, uid, header

                      // match the id's to the Data from the API call
                      for (uid = 0; uid < uidList.length; uid++) {
                        for (row = 0; row < data.length; row++) {
                          if (data[row].uid === uidList[uid]) {
                            let rowData = {}
                            uidList.splice(uid, 1) // found this id so remove from list

                            // take data from query call that we want, make objects, push them to array
                            for (header = 0; header < headerList.length; header++) {
                              let niceName = headerList[header].niceName
                              let id = headerList[header].id
                              rowData[niceName] = data[row][id]
                            }
                            output.push(rowData)
                          }
                        }
                      }

                      resolve(output);
                }).then(output=>{
                         //base case
                        if (uidList.length === 0) {
                                resolveFinal(output);
                                return output;
                            } else {
                      offset += 100 // get next 100 results from query
                      // run next recursive call
                      rec(uidList, offset, output)
                    }
                        });
                    });
                    }
                    rec();
                })
            }
  1. 使用所有rec调用中共享的输出,而不是在每次rec调用中创建一个新的输出实例。
  2. 使用2个承诺一个用于最终响应,另一个用于中间响应。
  3. slice应该用作slice(1)才能工作

答案 1 :(得分:0)

您应该将较新的结果与您已有的结果连接起来。因此,在最后一行中,您无法使用newData解析,而是使用output.concat(newData)。另外,push在这里是错误的......您需要concat

应该提到你正在应用promise构造函数antipattern,即你创建了一个你可以使用的promise。不需要new Promise

以下是它的外观:

exportCSV (uidList = this.checkboxList.slice(), offset = 0) {
  // Get query, build request
  let request = {
    id: 'export',
    query: this.currentQuery.query,
    sort: this.currentQuery.sort,
    limit: 100, // how much data is returned
    offset: offset // pagination value
  }

  // using Vuex to fetch data, returns an array of objects.
  //   (don't create a new promise when can return an existing one)
  return this.$store.dispatch('show/fetchQuery', request).then(data => {
      // Basecase
      if (uidList.length === 0) {
        return [];
      }

      let headerList = this.shownHeaders // an array of column id's & thier 'nice names'
      let output = []
      let row, uid, header

      // match the id's to the Data from the API call
      for (uid = 0; uid < uidList.length; uid++) {
        for (row = 0; row < data.length; row++) {
          if (data[row].uid === uidList[uid]) {
            let rowData = {}
            uidList.splice(uid, 1) // found this id so remove from list

            // take data from query call that we want, make objects, push them to array
            for (header = 0; header < headerList.length; header++) {
              let niceName = headerList[header].niceName
              let id = headerList[header].id
              rowData[niceName] = data[row][id]
            }
            output.push(rowData);
            // Probably you can now break out of this loop as you
            //   will not expect a second match
            break;
          }
        }
      }

      // run next recursive call, return the promise
      return this.exportCSV(uidList, offset + 100).then(newData => {
        // append to previous results
        return output.concat(newData);
      })
  })
}