• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

zserge/lua-promises: A+ promises in Lua

原作者: [db:作者] 来自: 网络 收藏 邀请

开源软件名称(OpenSource Name):

zserge/lua-promises

开源软件地址(OpenSource Url):

https://github.com/zserge/lua-promises

开源编程语言(OpenSource Language):

Lua 100.0%

开源软件介绍(OpenSource Introduction):

lua-promises

Build Status

A+ promises in Lua

Why would I need promises?

Lua is normally single-threaded, so there is little need in asyncrhonous operations. However, if you use HTTP requests, or sockets, or other types of I/O - most likely your library would have asynchronous API:

readfile('file.txt', function(contents, err)
	if err then
		print('Error', err)
	else
		-- process file contents
	end
end)

Using callbacks like this can quickly become problematic (once you need to make multiple asyncrhonous actions depending on each other results). Let's imagine some protocol where we need to connect to the remote peer, perform some authentication, then send a request and finally receive some response:

connect(function(status, err)
	if err then .... end
	auth(function(token, err)
		if err then ... end
		request(token, function(res, err)
			if err then ... end
			handleresult(res)
		end)
	end)
end)

Here's how the code could be rewritten using promises API:

connect():next(function(status)
	return auth()
end):next(function(token)
	return request(token)
end):next(function(result)
	handleresult(res)
end, function(err)
	...handle error...
end)

This is cleaner and more readable, since it doesn't use lost of nested callbacks. Also it has a single place to handle all errors.

The idea is that each function return an object which can be later resolved or rejected. Various callbacks could be added to the object to get notified when the object is resolved. Such objects are called promises, deferred objects, thennables - all these names describe pretty much the same behavior.

Install

In terminal:

luarocks install --server=http://luarocks.org/dev lua-promises

In Lua code:

local deferred = require('deferred')

API

Create new promises:

  • d = deferred.new() - returns a new promise object d
  • d = deferred.all(promises) - returns a new promise object d that is resolved when all promises are resolved/rejected.
  • d = deferred.first(promises) - returns a new promise object d that is resolved as soon as the first of the promises gets resolved/rejected.
  • d = deferred.map(list, fn) - returns a new promise object d that is resolved with the values of sequential application of function fn to each element in the list. fn is expected to return promise object.

Resolve/reject:

  • d:resolve(value) - resolve promise object with value
  • d:reject(value) - reject promise object with value

Wait for the promise object:

  • d:next(cb, [errcb]) - enqueues resolve callback cb and (optionally) a rejection callback errcb. Resolve callback can be nil.

Example

local deferred = require('deferred')

--
-- Converting callback-based API into promise-based is very straightforward:
-- 
-- 1) Create promise object
-- 2) Start your asynchronous action
-- 3) Resolve promise object whenever action is finished (only first resolution
--    is accepted, others are ignored)
-- 4) Reject promise object whenever action is failed (only first rejection is
--    accepted, others are ignored)
-- 5) Return promise object letting calling side to add a chain of callbacks to
--    your asynchronous function

function read(f)
	local d = deferred.new()
	readasync(f, function(contents, err)
		if err == nil then
			d:resolve(contents)
		else
			d:reject(err)
		end
	end)
	return d
end

-- You can now use read() like this:
read('file.txt'):next(function(s)
	print('File.txt contents: ', s)
end, function(err)
	print('Error', err)
end)

Chaining promises

Promises can be chained (read A+ specs for more details). It's convenient when you need to do several asynchronous actions sequentially. Each callback can return another promise object, then further callbacks could wait for it to become resolved/rejected:

-- Reading two files sequentially:
read('first.txt'):next(function(s)
	print('File 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)

Processing lists

You can process a list of object asynchronously, so the next asynchronous action is started only when the previous one is successfully completed:

local items = {'a.txt', 'b.txt', 'c.txt'}
-- Read 3 files, one by one
deferred.map(items, read):next(function(files)
	-- here files is an array of file contents for each of the files
end, function(err)
	-- handle reading error
end)

Waiting for a group of promises

You may start multiple asynchronous actions in parallel and wait for all of them to complete:

deferred.all({
	http.get('http://example.com/first'),
	http.get('http://example.com/second'),
	http.get('http://example.com/third'),
}):next(function(results)
	-- handle results here (all requests are finished and there has been
	-- no errors)
end, function(results)
	-- handle errors here (all requests are finished and there has been
	-- at least one error)
end)

Waiting for the first promise

In some cases it's handy to wait for either of the promises. A good example is reading with timeout:

-- returns a promise that gets rejected after a certain timeout
function timeout(sec)
	local d = deferred.new()
	settimeout(function()
		d:reject('Timeout')
	end, sec)
	return d
end

deferred.first({
	read(somefile), -- resolves promise with contents, or rejects with error
	timeout(5),
}):next(function(result)
	...file was read successfully...
end, function(err)
	...either timeout or I/O error...
end)

License

Code is distributed under MIT license.




鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
Neopallium/lua-llthreads: Low-Level threads(pthreads or WIN32 threads) for Lua.发布时间:2022-08-16
下一篇:
AyaseCore/mod-LuaEngine: Eluna module发布时间:2022-08-16
热门推荐
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap