【问题标题】:How to recursively call an asynchronous function?如何递归调用异步函数?
【发布时间】:2017-03-12 20:45:29
【问题描述】:

我已经定义了这个函数:

// 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) 要求将在检索方法的结果中提供的 id 传递到检查状态函数。

但是问题是这样的:

  1. 在第一次检查时,如果结果是“完成”,那么只需将来自checkRetreiveStatus 的结果对象返回到回调(包含结果)

  2. 但是如果结果没有完成,我需要再次调用checkRetrieveStatus...从内部checkRetrieveStatus

  3. 天真的方法是将原始checkRetrieveStatus 调用中的参数传递给checkRetrieveStatus 的新实例,但显然不可能知道这将被调用多少次。

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

【问题讨论】:

  • 调用一个函数并将回调传递给它。成功调用callback,内部回调,调用self(下一次迭代)。
  • 值得注意的是,递归在理论上是无限的。您可以为递归函数传递一个计数器,但想法是您不需要知道 cal 的数量。

标签: javascript node.js asynchronous recursion


【解决方案1】:

根据你的描述,听起来你只是想打电话给checkRetrieveStatus直到它完成,不是retrievecheckRetrieveStatus。对吗?

如果是这样,要做的事情是将状态检查提取到您自己的可以递归调用自身的函数中,如下所示:

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);
});

【讨论】:

  • 我怎么错过了?!
  • 这很好,感谢您的帮助。我从来没有想过递归调用调用 checkRetrieveStatus 的函数。
【解决方案2】:

最好拆分函数,这样你就不必重新进入顶部。类似这样的东西(没有尝试运行这个,所以只是明白了)

// 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);
});

【讨论】:

    猜你喜欢
    • 2016-09-21
    • 2019-02-20
    • 2023-03-23
    • 2020-09-08
    • 2013-12-07
    • 2017-06-27
    • 1970-01-01
    • 1970-01-01
    • 2022-01-27
    相关资源
    最近更新 更多