如何使用不同的参数递归调用异步方法

时间:2016-02-29 05:57:28

标签: javascript node.js promise protractor es6-promise

我有一个使用请求模块的休息调用方法,restRequest()返回响应作为promise,这是异步方法,我必须在获取每个结果并将结果传递给每个结果后,使用不同的参数递归调用此方法同样的方法。

示例代码:

restRequest(url, "POST").then(function(response) {
   restRequest(secondUrl, 'GET', response).then(function(response2) {

   }):
});

这是否有效,或者还有其他任何东西可以解决这个问题。

5 个答案:

答案 0 :(得分:4)

我会将async库用于此

特别是waterfall

哪个会像

一样
async.waterfall([
    function firstRequest(callback) {

         restRequest(url, "POST").then(function(response) {
               callback(null, response);
         });
    },
    function secondRequest (data, callback) {
         restRequest(secondUrl, 'GET', data).then(function(response2) {
               callback();
         });
    }
], function (err, result) {
    // Handle err or result
});

很抱歉我在手机上格式化了。

您可以从上面的链接中了解async.waterfall的工作原理。

你的方法有效,但取决于你有多少请求你最终可能会有一个很深的回调地狱

但是既然你正在使用promises,你就可以像

一样返回你的承诺链
restRequest(url, "POST")
.then(function(resp) { 
    return restRequest(secondUrl, "GET", resp);
})
.then(function(resp) {
    return restRequest(thirdUrl, "GET", resp);
});
.then(function(resp) {
    // do whatever keep the chain going or whatever 
})
.catch(function(error) {
     // if any of the promises error it will immediately call here. 
});

通过承诺,您可以在promise内返回新的.then,并保持链无限延伸。

我只是偏向于异步,因为我认为它确实提高了正确使用时的可读性。

答案 1 :(得分:1)

你可以做点什么:

let requestParams = [
  [url, 'POST'],
  [secondUrl, 'GET'],
  ...
];

function callRecursive(response){
  if(!requestParams.length) return Promise.resolve(response);
  let params = requestParams.shift();
  if(response)  params.push(response);
  return restRequest(...params).then(callRecursive);
}

callRecursive().then(successCallbk).catch(errCallBk);

答案 2 :(得分:0)

您可以向bind提供一个或多个参数到您的部分应用函数。

restRequest(url,"POST").then(restRequest.bind(this,secondUrl, "GET"))
                       .then(restRequest.bind(this,thirdUrl, "GET"));

答案 3 :(得分:0)

由于这些是串行发射的,你真正拥有的是一个简单的函数链(一些返回promise,有些可能没有)可以组合(或序列,在这里),我发现这是一个简洁的方法隔离出你想要发生的一切,然后根据需要组合行为。它仍然是引擎盖下的Promise链,但表现为一系列。首先,一些实用方法可以帮助:

var curry = (f, ...args) => 
          (f.length <= args.length) ? f(...args) : (...more) => curry(f, ...args, ...more);
var pipeP = (...fnlist) =>
          acc => fnlist.reduce( (acc,fn) => acc.then(fn), Promise.resolve(acc));

然后

//make restRequest only return a Promise once it's given its 3rd argument
var restRequest = autocurry(restRequest);

//define what our requests look like
var request1 = restRequest('firstUrl', "POST");//-> curried function, not yet called
var request2 = restRequest('secondUrl', 'GET');//-> curried function, not yet called

//define some simple methods to process responses
var extractURL = x => x.url;//-> simple function
var extractData = x=> x.data;//-> simple function

//final behaviors, i.e. do something with data or handle errors
//var handleData = ... //-> do something with "data"
//var handleError = ... //-> handle errors

//now, create a sort of lazy program chain waiting for a starting value
//that value is passed to request1 as its 3rd arg, starting things off
var handleARequest = pipeP(request1, extractURL, request2, extractData);

//and execute it as needed by passing it a starting request
handleARequest({postdata:5}).then(handleData).catch(handleErrors);

答案 4 :(得分:0)

递归是最明显的方法,但它不是必需的。另一种方法是通过减少已知参数数组(网址和方法)来构建.then()链。

此过程在&#34; The Collection Kerfuffle&#34;下显示here

function asyncSequence(params) {
    return params.reduce(function(promise, paramObj) {
        return promise.then(function(response) {
            return restRequest(paramObj.url, paramObj.method, response);
        });
    }, Promise.resolve(null)); // a promise resolved with the value to appear as `response` in the first iteration of the reduction.
}

这将满足任意数量的请求,具体取决于params数组的长度。

请致电如下:

var params = [
    {url:'path/1', method:'POST'},
    {url:'path/2', method:'GET'},
    {url:'path/3', method:'POST'}
];

asyncSequence(params).then(function(lastResponse) {
    //all successfully completed
}).catch(function(e) {
    // something went wrong
});