Excel 异步VBA函数

Excel 异步VBA函数,excel,vba,asynchronous,Excel,Vba,Asynchronous,我有一个VBA函数,它应该从用户的单元格中获取一些信息,用这些信息发出POST请求,然后在输出单元格中打印响应 要求用户一次能够发出大约2000个请求,所以我想让请求异步以帮助提高性能 现在,我有一个函数ConnectToAPI,它发出异步请求,然后将响应传递给回调函数。我遇到的问题是,数据存在于回调函数中,但我需要它存在于查询函数中才能返回它 Function Query(ID, quote, field) Application.Volatile Query = ConnectT

我有一个VBA函数,它应该从用户的单元格中获取一些信息,用这些信息发出POST请求,然后在输出单元格中打印响应

要求用户一次能够发出大约2000个请求,所以我想让请求异步以帮助提高性能

现在,我有一个函数ConnectToAPI,它发出异步请求,然后将响应传递给回调函数。我遇到的问题是,数据存在于回调函数中,但我需要它存在于查询函数中才能返回它

Function Query(ID, quote, field)  
  Application.Volatile
  Query = ConnectToAPI(ID)
  Some logic with parsed data from callback
End Function


Function ConnectToAPI(ID)

    Dim Request As New WebRequest
    Dim Client As New WebClient
    Client.BaseUrl = "http://www.endpoint.com"

    Dim Wrapper As New WebAsyncWrapper
    Dim Wrapper.Client = Client
    Dim Body As New Dictionary
    Body.Add "ID", ID
    Set Request.Body = Body
    Request.Method = HttpPost

    ConnectToAPI = Wrapper.ExecuteAsync Request, "CallbackFunction"
End Function

Function CallbackFunction
    Callback = Parsed Data
End function
最后在查询函数中,我想写

Query=(从回调解析的数据)

如何将回调中的数据传递回查询

单元格中必须有查询功能,这一点很重要。数据经常更新,因此我们希望客户端能够计算工作簿以获取最新数据

根据我目前的情况,我的想法是回调将把数据传递回ConnectToAPI,然后再传递给Query。但是,我的函数返回0,我认为这可能是函数尝试返回时解析的数据不可用

作为参考,我正在使用VBA Web库

WebAsyncWrapper.ExecuteAsync
有一个可选参数:
CallbackArgs
。使用此参数可传回ID或单元格地址

ExecuteAsync
有一个接收参数数组的示例回调函数

下面是如何将信息返回函数进行处理的方法

Sub ConnectToAPI(ID As Variant, quote As Variant, field As Variant, CellAddress As Variant)

    Dim Request As New WebRequest
    Dim Client As New WebClient
    Client.BaseUrl = "http://www.endpoint.com"

    Dim Wrapper As New WebAsyncWrapper

    Dim Body As New Dictionary

    Body.Add "ID", ID
    Set Request.Body = Body
    Request.Method = HttpPost
    Set Wrapper.Client = Client
    Wrapper.ExecuteAsync Request, "Callback", Array(ID, CellAddress)
End Sub

Public Function Callback(Response As WebResponse, Args As Variant)
    Dim ID As Variant, CellAddress As Variant
    ID = Args(0)
    CellAddress = Args(1)
    With Worksheets("Web Requests")
        .Range(CellAddress).Value = Response
        .Range(CellAddress).Offset(0, 1).Value = ID
    End With
End Function

将用户定义的函数标记为volatile。每当在工作表的任何单元格中进行计算时,必须重新计算volatile函数。只有当输入变量发生变化时,才会重新计算非易失性函数。如果此方法不在用于计算工作表单元格的用户定义函数中,则此方法无效

我不建议尝试使用UDF作为工作表函数来返回web请求<代码>应用程序。Volatile将导致每次更改值时刷新所有2000个查询。当第一个查询更新时,所有其他查询都将刷新。这将导致无限循环并使应用程序崩溃

Function Query(ID, quote, field)  
  Application.Volatile
  Query = ConnectToAPI(ID)
  Some logic with parsed data from callback
End Function
使用
工作表\u Change
事件将使用户能够更新信息,而不会出现与
Application.Volatile
相关的问题

Private Sub Worksheet_Change(ByVal Target As Range)
    If Not Intersect(Target, Columns("A")) Is Nothing Then
        If Target.Count = 1 Then
            Debug.Print Target.Value, Target.Address
        End If
    End If
End Sub

最后,我用API调用的响应值填充了一个字典,然后在回调中递归调用查询函数


查询检查响应值是否在字典中,如果在字典中,则返回它。如果没有,它将连接到api,回调将值放入字典,并再次调用查询函数。

一些问题,1)什么是“Post请求”?具体一点或者提供一个链接。2) 您在这里谈论的很多内容都非常不清楚,请提供一些代码和/或示例。您可能正在谈论通过HTTP向web服务器发送POST请求吗?您必须建立请求的全局“映射”(可能包括响应中返回的请求“ID”)这表示响应的目标单元格。我们需要一些代码来帮助您,但如果您想要异步VBA代码,则需要使用异步API,并查看类模块、
Event
RaiseEvent
with events
关键字。Yes@RBarryYoung。我编辑了我的问题以反映这一点。谢谢TinMan。让我来确认一下,我明白了。您是否建议我传入一个单元格地址,并将回调对该单元格的响应写在一个单独的表中(在您的示例中是Web请求)?如果我是正确的,我将能够在函数中使用该值,但前提是它从回调中及时可用,因此我认为我也会遇到同样的问题。至于Application.Volatile,这是老板对我的限制。我同意你的看法,但她坚持要这样做。@KWalsh:我是TinMan关于
应用程序的第二、第三和第四个说法。在这种情况下,我会以书面形式要求您的上司提供使用
Application.Volatile
的“指导”,并要求她对性能问题承担全部责任。严重地-
应用程序。Volatile
确实是个坏消息-就像硝化甘油一样,在极少数情况下有用,否则有很多更安全、更好的方法可以达到效果。除了TinMan提供的链接外,在搜索引擎中查找“Excel Volatile Functions”以更好地了解这意味着什么;因此,您将知道如何处理数据。在我的伪代码中,Web请求
是指使用
工作表\u Change
事件引用同一工作表。由于回调函数(实际上可以是子函数)需要位于公共模块中,因此它需要知道地址属于哪个工作表。如果您必须将UDF与
应用程序.Volatile一起使用,则可以让UDF返回目标单元格地址的值。我最初会将目标单元格的值设置为
加载…
,并在相邻单元格中跟踪请求的状态和时间戳。通过这种方式,您将能够在不触发重新查询的情况下更新UDF。您还需要一种机制来继续任何在工作簿关闭前未返回结果的查询。