这个方法的名字,让我产生很大兴趣。
仔细看完后,发现其只能在协程中使用,和C# 的 await关键字一样。
其实就是:在协程中,将 异步回调的方式 变为 同步等待的方式。
原理是:异步操作开始后将协程挂起,等异步操作完成调用回调方法后恢复协程。
一、源码分析
--传入一个async方法
local function async_to_sync(async_func, callback_pos)
--返回一个sync方法
return function(...)
--取当前正在运行的协程,若不存在则报错(说明只能在协程中使用!)
local _co = coroutine.running() or error ('this function must be run in coroutine')
--定义 结果
local rets
--定义 等待标记
local waiting = false
--定义 完成时的回调
local function cb_func(...)
if waiting then
--等待后回调的情况
--从挂起的位置恢复协程,并传递结果
assert(coroutine.resume(_co, ...))
else
--未等待就直接回调的情况,直接设置结果
rets = {...}
end
end
--参数列表 把 “回调” 加入参数列表(默认加入最后)
local params = {...}
table.insert(params, callback_pos or (#params + 1), cb_func)
--调用异步方法,把 “通过同步方法传入的参数” 和 “回调” 全部传给异步方法。
async_func(unpack(params))
--如果没有立即返回,则标记为等待并挂起
if rets == nil then
waiting = true
--挂起! "coroutine.yield()" 的返回值为 coroutine.resume 传入的第二个参数
rets = {coroutine.yield()}
end
--将结果同步返回
return unpack(rets)
end
end
二、使用层面分析
--异步充值
local function async_recharge(num, cb)
print('requst server...')
--HTTP请求
http.request(num, function()
--请求返回,执行异步完成的回调
cb(true, num)
end)
end
--购买的协程
local buy = function()
local recharge = async_to_sync(async_recharge)
--同步使用
local r1, r2 = recharge(10)
print('recharge result:', r1, r2)
end
--开始购买的协程
local co = coroutine.create(buy)
assert(coroutine.resume(co))
通常在使用时:
需要先确定需求,明确自己有一个这样的异步方法:async_recharge(num) ;
然后 增加一个额外的 完成回调 cb 用来在异步操作完成时调用, 变成 async_recharge(num, cb) ;
然后 异步转同步 local recharge = async_to_sync(async_recharge) ;
最后同步方式使用 local r1, r2 = recharge(10);
注意!这个“完成回调” 的参数(cb的参数),最终会成为同步方法的返回值(r1, r2)。