执行异步函数
本节内容可参考示例文件"CaseStudy\异步函数.Table"。
为更好地支持WebViewer的混合开发模式,避免界面假死,提升用户体验,Foxtable在新版本中引入了基于Await的异步编程模型。
现在,只需通过一个简单的注释标记'''Async,即可轻松实现自定义函数的异步调用,让耗时操作不再阻塞您的应用,异步编程从此不再复杂。
重要提示
:
1、Foxtable的异步编程是基于自定义函数的,有关自定义函数,请参考:自定义函数
2、高级开发指南中有关异步函数的介绍已经过时,今后请使用本节介绍的方式异步执行函数,要方便可靠很多。
异步执行
首先增加一个自定义函数Sum,这个函数非常耗时,代码为:
Dim
sum
As
Long
For
m
As
Integer
= 1
To
10000
For
i
As
Integer
= 0
To
1000000
sum = sum + i
Next
Next
Return
sum
然后在命令窗口测试这个函数:
Dim
sum
As
Long
= Functions.Execute("Sum")
Return
sum
我们要等待很久才能得到计算结果,且在等待的过程中,不能进行其他任何操作。
现在将测试代码改为:
'''Async
Dim
sum
As
Long
=
Await
Functions.ExecuteAsync("Sum")
Return
sum
这里有三处改变:
1、代码第一行加上了注释标记'''Async,告诉系统此代码段支持异步任务。
2、在函数调用的前面加上了Await关键词,用于等待异步任务完成并获取其结果。
3、调用函数的方法由Execute改为ExecuteAsync(请不要和以前的AsyncExecute混淆了)
再次运行修改后的代码,您会发现虽然仍然需要等待很久才能得到计算结果,但在等待的过程中,Foxtable的界面不会卡死,您可以正常进行其他操作。这就是异步执行的魅力所在——它将耗时任务放到了后台运行,避免了阻塞主界面线程。
前面的3处改变,除了3是必须的,1和2都不是必须的,如果满足下述两个条件,则可以去掉1和2:
1、函数没有返回值,或者不需要获取函数返回值。
2、不需要等函数运行结束就执行后续代码。
例如我们定义一个异步函数msgSum,
这个函数没有返回值,代码为:
Dim
sum
As
Long
For
m
As
Integer
= 1
To
10000
For
i
As
Integer
= 0
To
1000000
sum = sum + i
Next
Next
MessageBox.Show("执行完毕,结果:"
& sum,
"提示",
MessageBoxButtons.OK, MessageBoxIcon.Information)
在命令窗口异步执行这个函数:
Functions.ExecuteAsync("msgSum")
过一段时间会提示计算结果,在等待
期间依然可以进行其他操作。
重要提示:
凡是用到Await关键词的代码,不管是命令窗口、自定义函数还是事件代码,第一行必须是注释标记:'''Async
命名规范
我们需要遵守一个规范:凡是要异步执行的函数,后缀名都用"Async"。
现在我们新增一个函数,代码和Sum函数完全一样,名称为"SumAsync"。
尽管函数名是"Sum"也好,是"SumAsync"也好,都不会有任何影响,但是SumAsync能让后来者一眼看出:函数作者希望你异步执行这个函数。
现在命令窗口的测试代码为:
'''Async
Dim
sum
As
Long
=
Await
Functions.ExecuteAsync("SumAsync")
Return
sum
我们通过ExecuteAsync和SumAsync,确保后来者一眼就能看出,这里在执行一个异步函数,当然通过Await也可以看出,但正如前面所言,Await不是必须的。
这个后来者大概率是你自己,所以规范一点可利人利己。
关于Await
Await用于等待异步函数运行结束并获得返回值(如果有的话)。
所以Await关键词并不是必须的,如果你不需要获得异步函数的返回值,或者异步函数根本没有返回值,且你希望不等异步函数结束就开始运行后面的代码,那么就可以去掉Await关键词
。
例如我们定义一个异步函数SubAsync,代码为:
'''Async
Await
System.Threading.Tasks.Task.Delay(5000)
'暂停5秒,模拟高耗时操作
在命令窗口执行下面的代码:
Output.Show("开始执行:"
&
Date.Now)
Functions.ExecuteAsync("SubAsync")
Output.Show("执行结束:"
&
Date.Now)
可以看到输出的开始时间和结束时间是相同的,因为这里没有Await关键词,所以并没有等异步函数运行结束就输出了结束时间。
如果将代码改为:
'''Async
Output.Show("开始执行:"
&
Date.Now)
Await
Functions.ExecuteAsync("SubAsync")
Output.Show("执行结束:"
&
Date.Now)
则结束时间会比开始时间晚5秒,因为要等异步函数运行结束才输出结束时间,而异步函数消耗的时间为5秒。
但不管有没有Await关键词,只要你是用ExecuteAsync方法执行函数,函数都是异步执行的,所以在等待的过程中,
界面都不会卡死,你可以继续进行其他操作。
使用异步函数
异步函数最终是为同步代码服务的。
异步函数可以在命令窗口执行,也可以直接用在所有事件代码中,不需要特别的处理,只需记得需要Await的时候,代码的第一行必须是注释标记:'''Async
我们可以用个小例子来测试一下(本示例文件的窗口"异步函数"):
新建一个窗口,插入一个Button和一个TextBox,前者用于执行异步函数,后者用于显示计算结果。
Button按钮的代码设置为:
'''Async
e.Sender.Enabled =
False
e.Sender.Text =
"正在计算,请稍候..."
Dim
result
As
Long
=
Await
Functions.ExecuteAsync("SumAsync")
e.Form.Controls("TextBox1").Value
= result
e.Sender.Text =
"开始计算"
e.Sender.Enabled =
True
单击按钮开始计算后,程序不会失去响应,你可以继续进行其他操作,一段时间后TextBox会显示计算结果。