如何递归调用异步函数?

时间:2016-10-30 15:48:47

标签: javascript node.js asynchronous recursion

我已经定义了这个功能:

// retrieves zip of package manifest supplied

var retrieveZip = function(metadataClient, args, callback) {
  metadataClient.retrieve(args, function(err, result) {
    metadataClient.checkRetrieveStatus({id: result.result.id, includeZip: 'true'}, function(err, result) {
      if(result.result.done) {
        return callback(result);
      }
      // else check again!(how??)
    });
  });
}

retrieveZip(metadataClient, args, function(result) {
      console.log(result);
});

这个想法是客户端将尝试根据args中提供的元数据检索zip文件。 API文档(Salesforce SOAP API)要求将retireve方法的结果中提供的id传递给检查状态函数。

但问题是这样:

  1. 在第一次检查时,如果结果已完成'然后从checkRetreiveStatus(包含结果)
  2. 返回结果对象的回调
  3. 但如果结果尚未完成,我需要再次致电checkRetrieveStatus ...来自checkRetreiveStatus内部
  4. 天真的方法是将原始checkRetreiveStatus调用中的参数传递给checkRetreiveStatus的新实例,但显然无法知道调用它的次数。< / LI>

    听起来我需要一个递归的解决方案吗?使用while循环会引入异步调用问题吗?

2 个答案:

答案 0 :(得分:2)

根据您的说明,您只是想要致电checkRetrieveStatus直到完成, retrieve checkRetrieveStatus 。这是对的吗?

如果是这样,那么要做的是将状态检出提取到你自己的函数中,该函数可以递归调用自身,如下所示:

var checkStatus = function(metadataClient, id, callback) {
    metadataClient.checkRetrieveStatus({ id: id, includeZip: 'true' }, function(err, result) {
        if (result.result.done) {
            callback(result); 
        } else {
            checkStatus(metadataClient, id, callback);
        }
    });
};

var retrieveZip = function(metadataClient, args, callback) {
  metadataClient.retrieve(args, function(err, result) {
      checkStatus(metadataClient, result.result.id, callback);
  });
}

retrieveZip(metadataClient, args, function(result) {
      console.log(result);
});

如果您在重复轮询结果时担心会占用系统资源,则可以在检查之间加入延迟:

var checkStatus = function(metadataClient, id, callback) {
    metadataClient.checkRetrieveStatus({ id: id, includeZip: 'true' }, function(err, result) {
        if (result.result.done) {
            callback(result); 
        } else {
            setTimeout(function () {
                checkStatus(metadataClient, id, callback);
            }, 100);
        }
    });
};

var retrieveZip = function(metadataClient, args, callback) {
  metadataClient.retrieve(args, function(err, result) {
      checkStatus(metadataClient, result.result.id, callback);
  });
}

retrieveZip(metadataClient, args, function(result) {
    console.log(result);
});

答案 1 :(得分:0)

最好分割功能,这样你就不必重新输入top.something这样的东西(不试图运行它,所以只是得到这个想法)

// retrieves zip of package manifest supplied

var retrieveZip = function(metadataClient, args, callback) {
  metadataClient.retrieve(args, function(err, result) {
    doCheck(result,function(res){
       callback(res)
    })

  });
}


function doCheck(result,cb){
 metadataClient.checkRetrieveStatus({id: result.id, includeZip: 'true'}, function(err, innerResult) {
     if(result.result.done) {
            return cb(result);
      }else{
    doCheck( innerResult ,cb)
    }
  });
}

retrieveZip(metadataClient, args, function(result) {
      console.log(result);
});