Lua Academy · 课时

使用协程实现 Async/Await

创建 async() 和 await() 辅助函数,以挂起和恢复协程。

第 2 / 4 课13 个步骤

使用协程实现 Async/Await 是 CoddyKit 上的免费 Lua Academy 课时。 这是第 2 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Lua Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Lua Academy 课程共包含 4 节课。

异步/等待思想

异步/等待是一种编程模型,其中异步操作看起来像同步代码。在 Lua 中,协程提供了 yield/resume 机制,可以自然地实现这一模型。

等待函数

await(future) 会让当前协程执行 yield,并保存一个回调;未来结果完成时,该回调会恢复协程。

local function await(future)
  local co = coroutine.running()
  future.onComplete = function(result)
    coroutine.resume(co, result)
  end
  return coroutine.yield()
end

异步函数包装器

async(fn) 会包装一个函数,使其在由调度器管理的新协程中运行。

local function async(fn)
  return function(...)
    local co = coroutine.create(fn)
    local ok, err = coroutine.resume(co, ...)
    if not ok then print("async error:", err) end
    return co
  end
end

简单的未来结果对象

未来结果对象表示尚未产生的结果。稍后调用 complete,它就会恢复所有等待中的协程。

local function newFuture()
  local f = {done=false, value=nil, waiters={}}
  f.complete = function(val)
    f.done = true; f.value = val
    for _, cb in ipairs(f.waiters) do cb(val) end
  end
  f.andThen = function(cb)
    if f.done then cb(f.value)
    else f.waiters[#f.waiters+1] = cb end
  end
  return f
end

等待的实际应用

编写看起来按顺序执行、但内部会执行 yield 和恢复操作的异步代码。

local fetchData = async(function(url)
  local result = await(httpGet(url))  -- yields
  local parsed = await(parseJSON(result))  -- yields again
  print("Got:", parsed.name)
end)
fetchData("http://example.com/api")

错误传播

通过未来结果对象传递错误:如果操作失败,就带着错误标志和错误消息恢复协程。

local function awaitSafe(future)
  local co = coroutine.running()
  future.onComplete = function(ok, result)
    coroutine.resume(co, ok, result)
  end
  return coroutine.yield()
end

顺序执行与并行执行

对于有依赖关系的操作,请按顺序使用 await。对于相互独立的操作,请启动两个协程,并等待一个合并结果对象。

Promise.all 模式

运行多个异步任务,并使用计数器形式的未来结果对象等待它们全部完成。

local function all(futures)
  local results = {}
  local count = #futures
  local combined = newFuture()
  for i, f in ipairs(futures) do
    f:andThen(function(v)
      results[i] = v
      count = count - 1
      if count == 0 then combined.complete(results) end
    end)
  end
  return combined
end

取消

在恢复协程之前将其标记为已取消,即可实现取消。协程会检查该标志并提前返回。

与输入/输出集成

与非阻塞输入/输出集成:当输入/输出调用可能阻塞时,执行 yield,并注册一个回调,在数据可用时恢复协程。

与回调风格的比较

使用协程的异步/等待代码比嵌套回调可读性高得多。使用受保护调用处理错误,也比使用回调错误参数更简洁。

异步/等待问题

在基于协程的异步系统中,await(future) 会做什么?

回顾:使用协程实现异步/等待

将异步操作包装成未来结果对象,并在操作完成时恢复执行 yield 的协程,即可使用协程实现异步/等待。这样得到的代码看起来按顺序执行,实际上不会阻塞。

免费开始

用 AI 导师学习 Lua — 免费

在浏览器中编写并运行真实代码,获得全天候 AI 导师的即时帮助,并在网页或应用中继续学习。

课程
40
课程
159

常见问题解答

「使用协程实现 Async/Await」课时是免费的吗?

是的 — 「使用协程实现 Async/Await」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Lua Academy 课程的其余内容,请升级到 CoddyKit PRO。 Lua Academy 课程共包含 4 节课。

「使用协程实现 Async/Await」这节课中我会学到什么?

创建 async() 和 await() 辅助函数,以挂起和恢复协程。 你通过在浏览器中直接运行的动手代码来练习 Lua Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 Lua Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 Lua Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 2 节课,共 4 节。

「使用协程实现 Async/Await」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 Lua Academy 课中编写并运行代码吗?

能。每节 Lua Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 构建简单事件循环
  2. 使用协程实现 Async/Await
  3. 类似 Promise 的模式
  4. 使用 luasocket 实现非阻塞 I/O
← 返回 Lua Academy