博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
JavaScript怎么使用循环代替(异步)递归
阅读量:5875 次
发布时间:2019-06-19

本文共 2622 字,大约阅读时间需要 8 分钟。

问题描述

在开发过程中,遇到一个需求:在系统初始化时通过http获取一个第三方服务器端的列表,第三方服务器提供了一个接口,可通过分页形式获取列表。

这里有两个问题:

  • 未知的列表数量。就算已知总数量,如果数据量巨大,也不应该一次获取全部信息。
  • 在node.js中,http是异步的。

假设该接口为:

GET http://www.example.com/api/listQUERY page=PAGE_INDEX&size=PAGE_SIZERETURN {
data: [DATA,...], page: {
page: PAGE_INDEX, size: PAGE_SIZE}}复制代码

期望结果:

所有的数据

[DATA, ...]复制代码

目的

借以该问题,了解关于递归的更多知识。

解决方案

  • callback + 辅助变量

    let request = require('superagent')  let api = 'http://www.example.com/api/list'  function getList (page, size, data = [], cb) {    request(api).query({page, size})      .then(({body}) => {        if (body.data && body.data.length) {          // getList(page++, size, data.concat(body.data), cb)          getList(++page, size, data.concat(body.data), cb)        } else {          cb(data)        }      })  }  getList(1, 15, [], (data) => {      console.log(data)   })复制代码

    还是能够理解,不断请求,并把获得的数据传到下一个请求;直到返回数据为空时终止,并返回累加的数据。就算不用promise而是普通回答(如使用end方法)也是可以的,可以不依赖函数返回值。但是需要一个没有意义的变量。

  • promise

    let request = require('superagent')  let api = 'http://www.example.com/api/list'  function getList (page, size) {    return request(api).query({page, size})      .then(({body}) => {        if (body.data && body.data.length) {          return getList(++page, size)            .then((data) => {               return body.data.concat(data)            })        } else {           return []        }      })  }  getList(1, 15).then((data) => {    console.log(data)  })复制代码

    相比较上面的方法,不在需要辅助变量和回调函数,看起来更像普通的递归。但是由于promise中不断return,使得代码难以理解,且容易忽略掉数据为空时else判断。

  • generater

    let request = require('superagent')  let co = require('co')  let api = 'http://www.example.com/api/list'  function* getList (page, size) {    let {body} = yield request(api).query({page, size})    if (body.data && body.data.length) {      return body.data.concat(yield getList(++page, size))    } else {      return []    }  }  co(function *() {    let data = yield getList(1, 100)    console.log(data.length);  })复制代码

    同步方式的代码,更加方便阅读和理解。但是复杂的generater函数需要使用相应的环境才能运行,如co,最不喜欢的就是在数组的一些遍历方法中不能使用。

  • async + await 和generater差不多,也需要相应的环境,但是可以在数组的遍历方法中使用。

思考

对于一下这句话,我总是抱着怀疑的,因为很多时候我会很快想到使用递归可以解决,而不会想到使用循环来解决。在JavaScript中,那些异步的递归函数怎么才能转换为循环呢?

递归和循环两者完全可以互换

在一次面试中,面试官给我描述了这么一个需求:

一个函数期望通过输入两个数,返回一个数组,且不能使用循环。第一个参数x表示结果数组中元素,第二个参数n代表数组长度。

我第一反应就是使用递归,或者使用数组的遍历方法。说真的,我真的没有那么一丢丢的想到循环,然而循环貌似最应该容易想到...。

// 循环function repeat (x, n) {  let arr = []  while (arr.length < n) {    arr.push(x)  }  return arr}// 递归function repeat (x, n) {  return n > 0 ? [x].concat(repeat(x, --n)) : []}// 数组function repeat (x, n) {  new Array(n).fill(x)}复制代码

那么像上面那个请求的异步递归,如果没有ECMScript 2015(使用回调),该怎么写成循环呢?

经典广告词:想不出来


希望有人可以帮助我

转载地址:http://uckix.baihongyu.com/

你可能感兴趣的文章
安装gulp及相关插件
查看>>
如何在Linux用chmod来修改所有子目录中的文件属性?
查看>>
Applet
查看>>
高并发环境下,Redisson实现redis分布式锁
查看>>
乌克兰基辅一世遗修道院起火 现场火光照亮夜空
查看>>
[iOS 10 day by day] Day 2:线程竞态检测工具 Thread Sanitizer
查看>>
Centos/Ubuntu下安装nodejs
查看>>
关于浏览器的cookie
查看>>
Hyper-V 2016 系列教程30 机房温度远程监控方案
查看>>
国内先进的智能移动广告聚合平台-KeyMob聚合
查看>>
我的友情链接
查看>>
我的友情链接
查看>>
PHP - 如何打印函数调用树
查看>>
js闭包
查看>>
寒假。3.3.G - Common Child (最大公共子序)
查看>>
设计模式学习笔记--原型模式
查看>>
.Net 通过MySQLDriverCS操作MySQL
查看>>
JS Cookie
查看>>
ubuntu Unable to locate package sysv-rc-conf
查看>>
笔记:认识.NET平台
查看>>