lua-promises
lua-promises copied to clipboard
Runtime errors are not reported in chained promises
If I make a programming error in the first promise (in a promise chain) I get an expected runtime error but if I make a programming error in the second promise I get no runtime error.
I slightly modifed your chained promises example to verify this:
local deferred = require "lib.deferred"
function readasync(filename, cb)
if filename == 'first.txt' then
call_missing_function()
cb("content1", nil)
else
--call_missing_function()
cb("content2", nil)
end
end
function read(filename)
local d = deferred.new()
readasync(filename, function(contents, err)
if err == nil then
d:resolve(contents)
else
d:reject(err)
end
end)
return d
end
read('first.txt'):next(function(s)
print('First file:', s)
return read('second.txt')
end):next(function(s)
print('Second file:', s)
end):next(nil, function(err)
-- error while reading first or second file
print('Error:', err)
end)
When I run the above I get an expected runtime error:
nov. 02 06:38:45.241 ERROR: Runtime error
/Users/jocke/src/blackmode/trunk/app/ui2/main.lua:5: attempt to call global 'call_missing_function' (a nil value)
stack traceback:
/Users/jocke/src/blackmode/trunk/app/ui2/main.lua:5: in function 'readasync'
/Users/jocke/src/blackmode/trunk/app/ui2/main.lua:15: in function 'read'
/Users/jocke/src/blackmode/trunk/app/ui2/main.lua:25: in main chunk
If I change the readsync function above to this:
function readasync(filename, cb)
if filename == 'first.txt' then
--call_missing_function()
cb("content1", nil)
else
call_missing_function()
cb("content2", nil)
end
end
Then I just get the custom error message and no run-time error:
Error: /Users/jocke/src/blackmode/trunk/app/ui2/main.lua:8: attempt to call global 'call_missing_function' (a nil value)
I this to be expected?
Kind regards
I ended up removing all the pcalls i deferred.lua. Works like a charm.
Sorry for a late reply.
You're right, this may be confusing. According to the A+ spec:
If either onFulfilled or onRejected throws an exception e, promise2 must be rejected with e as the reason.
That's why throwing no runtime errors and passing them to error callback is the expected behavior. The catch is that you first function is called like a normal function and thus there is no outer handler to catch the runtime error.
I've just pushed a tiny change to the library. Now deferred.new()
may (and should) receive a function that deals with the deferred object. There is no need to create deferred object manually anymore. With this modification your example should be rewritten like this:
local deferred = require "deferred"
function readasync(filename, cb)
if filename == 'first.txt' then
call_missing_function()
cb("content1", nil)
else
--call_missing_function()
cb("content2", nil)
end
end
function read(filename)
return function(d)
readasync(filename, function(contents, err)
if err == nil then
d:resolve(contents)
else
d:reject(err)
end
end)
end
end
deferred.new(read('first.txt')):next(function(s)
print('First file:', s)
return read('second.txt')
end):next(function(s)
print('Second file:', s)
end):next(nil, function(err)
-- error while reading first or second file
print('Error:', err)
end)