Skip to content

Commit 54a4529

Browse files
committed
support await in functions called from javascript
1 parent 4cf40cb commit 54a4529

File tree

2 files changed

+12
-63
lines changed

2 files changed

+12
-63
lines changed

README.md

Lines changed: 1 addition & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ npm test # ensure everything it's working fine
190190

191191
### Promises
192192

193-
Promises can be await'd from Lua with some caveats detailed in the below section. To await a Promise call `:await()` on it which will yield the Lua execution until the promise completes.
193+
Promises can be await'd from Lua. To await a Promise call `:await()` on it which will yield the Lua execution until the promise completes.
194194

195195
```js
196196
const { LuaFactory } = require('wasmoon')
@@ -206,61 +206,3 @@ try {
206206
lua.global.close()
207207
}
208208
```
209-
210-
### Async/Await
211-
212-
It's not possible to await in a callback from JS into Lua. This is a limitation of Lua but there are some workarounds. It can also be encountered when yielding at the top-level of a file. An example where you might encounter this is a snippet like this:
213-
214-
```js
215-
local res = sleep(1):next(function ()
216-
sleep(10):await()
217-
return 15
218-
end)
219-
print("res", res:await())
220-
```
221-
222-
Which will throw an error like this:
223-
224-
```
225-
Error: Lua Error(ErrorRun/2): cannot resume dead coroutine
226-
at Thread.assertOk (/home/tstableford/projects/wasmoon/dist/index.js:409:23)
227-
at Thread.<anonymous> (/home/tstableford/projects/wasmoon/dist/index.js:142:22)
228-
at Generator.throw (<anonymous>)
229-
at rejected (/home/tstableford/projects/wasmoon/dist/index.js:26:69)
230-
```
231-
232-
Or like this:
233-
234-
```
235-
attempt to yield across a C-call boundary
236-
```
237-
238-
You can workaround this by doing something like below:
239-
240-
```lua
241-
function async(callback)
242-
return function(...)
243-
local co = coroutine.create(callback)
244-
local safe, result = coroutine.resume(co, ...)
245-
246-
return Promise.create(function(resolve, reject)
247-
local function step()
248-
if coroutine.status(co) == "dead" then
249-
local send = safe and resolve or reject
250-
return send(result)
251-
end
252-
253-
safe, result = coroutine.resume(co)
254-
255-
if safe and result == Promise.resolve(result) then
256-
result:finally(step)
257-
else
258-
step()
259-
end
260-
end
261-
262-
result:finally(step)
263-
end)
264-
end
265-
end
266-
```

src/type-extensions/function.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -211,11 +211,18 @@ class FunctionTypeExtension extends TypeExtension<FunctionType, FunctionDecorati
211211
callThread.setTimeout(Date.now() + this.options.functionTimeout)
212212
}
213213

214-
const status: LuaReturn = callThread.lua.lua_pcallk(callThread.address, args.length, 1, 0, 0, null)
215-
if (status === LuaReturn.Yield) {
216-
throw new Error('cannot yield in callbacks from javascript')
214+
const resumeResult: LuaResumeResult = callThread.resume(args.length);
215+
if (resumeResult.result === LuaReturn.Yield) {
216+
return new Promise(async (r) => {
217+
await callThread.run(0);
218+
if (callThread.getTop() > 0) {
219+
r(callThread.getValue(-1));
220+
return;
221+
}
222+
r(undefined);
223+
});
217224
}
218-
callThread.assertOk(status)
225+
callThread.assertOk(resumeResult.result)
219226

220227
if (callThread.getTop() > 0) {
221228
return callThread.getValue(-1)

0 commit comments

Comments
 (0)