【问题标题】:How to achieve recursive Promise calls in Node.js如何在 Node.js 中实现递归 Promise 调用
【发布时间】:2020-01-08 06:11:20
【问题描述】:

我正在调用一个 API,每次请求只能获取 1000 条记录, 我能够使用递归来实现这一点。

我现在正在尝试使用 Promise 来实现相同的目标,我对 Node.js 和 JavaScript 也很陌生。

我尝试在 if else 块中添加递归代码但失败了

var requestP = require('request-promise');

const option = {
    url: 'rest/api/2/search',
    json: true,
    qs: {
        //jql: "project in (FLAGPS)",
    }
}
const callback = (body) => {

    // some code
    .
    .
    .//saving records to file
    .
    //some code
    if (totlExtractedRecords < total) {  

        requestP(option, callback).auth('api-reader', token, true)
     .then(callback)
    .catch((err) => {
        console.log('Error Observed ' + err)
    })
    }
}

requestP(option).auth('api-reader', token, true)
    .then(callback)
    .catch((err) => {
        console.log('Error Observed ' + err)
    })

我想使用 Promise 并以同步方式执行该方法, 即我想等到记录全部导出到文件并继续我的代码

【问题讨论】:

  • 你可以尝试将callback 设为async 函数并在requestP 函数promise 上设置await
  • 你会发现this Q&A相关。如果您无法将那里的技术适应您的特定情况,请 lmk 和我今天晚些时候会尽力为您提供帮助。

标签: javascript node.js recursion promise


【解决方案1】:

使用 Amir Popovich 的反馈创建此代码

const rp = require('Request-Promise')
const fs = require('fs')

const pageSize = 200

const options = {
    url: 'https://jira.xyz.com/rest/api/2/search',
    json: true,
    qs: {
        jql: "project in (PROJECT_XYZ)",            
        maxResults: pageSize,
        startAt: 0,
        fields: '*all'
    },
    auth: {
        user: 'api-reader',
        pass: '<token>',
        sendImmediately: true
    }
}



const updateCSV = (elment) => {
    //fs.writeFileSync('issuedata.json', JSON.stringify(elment.body, undefined, 4))
}


async function getPageinatedData(resolve, reject, ctr = 0) {
    var total = 0

    await rp(options).then((body) => {
        let a = body.issues
        console.log(a)
        a.forEach(element => {
            console.log(element)
            //updateCSV(element)
        });

        total = body.total

    }).catch((error) => {
        reject(error)
        return
    })

    ctr = ctr + pageSize
    options.qs.startAt = ctr

    if (ctr >= total) {
        resolve();
    } else {
        await getPageinatedData(resolve, reject, ctr);
    }
}

new Promise((resolve, reject) => getPageinatedData(resolve, reject))
    .then(() => console.log('DONE'))
    .catch((error) => console.log('Error observed - ' + error.name + '\n' + 'Error Code - ' + error.statusCode));

【讨论】:

    【解决方案2】:

    使用您的代码,我对其进行了重构,如下所示。希望对你有帮助。

    const requestP = require('request-promise');
    const option = {
        url: 'rest/api/2/search',
        json: true,
        qs: {
            //jql: "project in (FLAGPS)",
        }
    };
    
    /* 
        NOTE: Add async to the function so you can udse await inside the function 
    */
    
    const callback = async (body) => {
    
        // some code
    
        //saving records to file
    
        //some code
    
        try {
            const result = await requestP(option, callback).auth('api-reader', token, true);
            if (totlExtractedRecords < total) {
                return callback(result);
            }
            return result;
        } catch (error) {
            console.log('Error Observed ' + err);
            return error;
        }
    }
    

    【讨论】:

      【解决方案3】:

      这是一个使用最新 NodeJS 功能的干净而漂亮的解决方案。 递归函数将继续执行,直到满足特定条件(在此示例中异步获取一些数据)。

      const sleep = require('util').promisify(setTimeout)
      
      const recursive = async () => {
        await sleep(1000)
        const data = await getDataViaPromise() // you can replace this with request-promise
      
        if (!data) {
          return recursive() // call the function again
        }
      
        return data // job done, return the data
      }
      

      递归函数可以如下使用:

      const main = async () => {
        const data = await recursive()
        // do something here with the data
      }
      

      【讨论】:

        【解决方案4】:

        我认为创建自己的 Promise 并在完成递归后简单地解决它会更好。这是一个简单的示例,仅供您理解该方法

        async function myRecursiveLogic(resolveMethod, ctr = 0) {
              // This is where you do the logic
              await new Promise((res) => setTimeout(res, 1000)); // wait - just for example
              ctr++;
              console.log('counter:', ctr);
        
              if (ctr === 5) {
                resolveMethod(); // Work done, resolve the promise
              } else {
                await myRecursiveLogic(resolveMethod, ctr); // recursion - continue work
              }
            }
        
        // Run the method with a single promise
        new Promise((res) => myRecursiveLogic(res)).then(r => console.log('done'));

        【讨论】:

        • 我对上述答案有几个问题。 1.resolveMethod是如何工作的? 2.你能解释一下最后一行吗?通常我们在 promise 中写 res()。
        • 你知道什么是承诺吗?如果没有,请在此处阅读:medium.com/javascript-scene/…。如果这样做,resolveMethod 是您要解决承诺时调用的方法。最后一行创建了一个新的 Promise 并将 resolve 方法作为参数传递给你的递归逻辑函数。您现在可以使用递归编写代码,完成后,您只需调用传递的 resolve 方法,外部的 promise 就会被解析。
        猜你喜欢
        • 2020-02-10
        • 2016-05-26
        • 2018-01-15
        • 2015-08-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-01-25
        • 2021-02-03
        相关资源
        最近更新 更多