Power Query 延迟递归

Power Query delayed recursion

我对 Power Query 还很陌生,想在 Excel 中拼凑一个小演示。

我有两个网络端点:我必须 post 一些内容到第一个端点,这给了我第二个端点的 url 然后我必须查询第二个端点的实际结果。第二个端点返回 json 响应,其中有一个字段表示结果是否准备就绪。如果结果准备好了,就可以进行处理,如果没有,应该稍后再查询端点。

这是我目前的代码:

let   
    apikey      = "MYAPIKEY",        
    proxyendpoint = "URL OF THE FIRST ENDPOINT",
    bytesbody   = File.Contents("FILE TO POST"),
    headers     = [#"Ocp-Apim-Subscription-Key" = apikey],
    bytesresp   = Web.Contents(proxyendpoint, [Headers=headers, Content=bytesbody]),    
    jsonresp    = Json.Document(bytesresp),    
    opLoc       = jsonresp[OperationLocation],
    getResult = (url) =>
        let           
           linesBody = Web.Contents(url, [Headers=headers]),
           linesJson = Json.Document(linesBody),
           resultStatus = linesJson[status],
           linesData = if (resultStatus = "Succeeded") then
                              linesJson[recognitionResult][lines]
                       else 
                              Function.InvokeAfter(()=>@getResult(url),#duration(0,0,0,5))
       in
          linesData,
   linesText = List.Transform(getResult(opLoc), each _[text]),   
   table = Table.FromList(linesText)
in
   table

我的问题是,当我检查 Fiddler 时,我看到第二个端点被查询过一次,我可以在响应中检查结果尚未准备好,数据加载 "hangs",但我看不到对第二个端点的任何额外调用,所以基本上我的递归调用没有被评估。

我做错了什么?

()=>在Function.InvokeAfter的第一个参数中,Function.InvokeAfter的结果将是函数getResult,而不是结果从得到结果。所以它应该被排除在外:

Function.InvokeAfter(@getResult(url),#duration(0,0,0,5))

事实证明我的代码基本上是正确的。问题是 Web.Contents() 做了一些内部缓存,这就是为什么我在 Fiddler 中看不到更多的调用,这就是为什么我的数据加载 "hang" (因为第一次递归退出标准是错误的并且结果被缓存,每个后续递归只使用相同的数据)。

我为延迟递归场景创建了一些 POC,奇怪的是,一切正常。我改变了一些东西,直到我找到了一个 POC 版本,其中唯一的区别是 Web.Contents() 调用。所以我搜索了这个特定问题并找到了 post here.

因此,正如此 post 中所建议的,我为每个 Web.Contents() 调用添加了一个新的 header 值,以避免响应被缓存(也稍微清理了代码):

let   
    apikey      = "MYAPIKEY",   
    proxyendpoint = "URL OF THE FIRST ENDPOINT",
    bytesbody   = File.Contents("FILE PATH TO BE POSTED"),
    headers     = [#"Ocp-Apim-Subscription-Key" = apikey],
    bytesresp   = Web.Contents(proxyendpoint, [Headers=headers, Content=bytesbody]),    
    jsonresp    = Json.Document(bytesresp),    
    opLoc = jsonresp[OperationLocation],  
    getResult = (url, apiKeyParam) =>
      let
        // note the extra header here, which is different in every call
        currentHeaders = [#"Ocp-Apim-Subscription-Key" = apiKeyParam, #"CacheHack" = Number.ToText(Number.Random())],
        linesBody = Web.Contents(url, [Headers=currentHeaders]),
        linesJson = Json.Document(linesBody),
        resultStatus = linesJson[status],
        result = if (resultStatus = "Succeeded") then linesJson[recognitionResult][lines]
                 else Function.InvokeAfter(()=>@getResult(url, apiKeyParam), #duration(0,0,0,5))
       in result,
    linesText = List.Transform(getResult(opLoc, apikey), each _[text]),   
    table = Table.FromList(linesText)    
 in table