Programming Lua like Javascript

I had a novel idea that I was thinking about, and I was wondering if there is a way to make scripts even faster (talking Javascript fast).

Anyone who programs in Javascript knows theres some things such as promises, callbacks, and even Async/Await. On Roblox, these don’t appear to be needed, as code won’t move on until it’s done with the line above. An example is if I make an http request using roblox’s httprequest system, the code below waits until the http request is processed. While this is extremely useful, I feel as though this could slow things down.

Is there a way to utilize Lua on roblox in a manner similar to javascript?

Thanks!

3 Likes

Dont use spawn(). Spawn has a built in wait() into it, and wait() is notorious for being unreliable.

Instead, use coroutines. You can create, pause, and wrap functions with them. Coroutines are instantaneous and don’t interrupt the rest of the thread, so they’re also useful for using while loops which would yield the script.

So with coroutines, you can run 2 seperate threads at the same time

https://developer.roblox.com/en-us/articles/Beginners-Guide-to-Coroutines/index.html

https://developer.roblox.com/en-us/api-reference/lua-docs/coroutine

1 Like

Someone actually created a nice library for promises : Promises and Why You Should Use Them,

1 Like

You can implement all of these in Lua, but it won’t necessarily make anything faster. The closest thing you’ll get to writing Lua code like Javascript is roblox-ts, which is a TypeScript to Roblox compiler.

2 Likes

IIRC lua is faster than javascript. Additionally there is no need for Async/Await (or as we like to call asynchronous programming) because lua has built in methods that allows us to multi thread. This is true, however you need to take precautions when taking certain suggestions from others.

Don’t ever do this. Never use spawn() because it has a built in wait(), which is unreliable. When your game gets bigger you will notice actions being executed slower. It is notorious. I recommend that you use coroutines, which executes instantly and does not interrupt the rest of the thread

Other than that, you should be good. Lua is a powerful programming language and it is capable of doing all.

4 Likes

Coroutines are not that great either since they obfuscate the stack trace, but never use spawns because the more you use the longer the built in wait will last, I would recommend a custom thread class using the run service like this: https://github.com/Sleitnick/AeroGameFramework/blob/master/src/ReplicatedStorage/Aero/Shared/Thread.lua

1 Like

Clearly if you can built your own custom class for multi-threading, that would be great. Other than that coroutines are the best option, and are far superior to spawn and delay (in terms of build in methods). I’ve never had any bad experiences when working with them, and is a good option for many developers out there

2 Likes

No there is no problem working with them its the debugging.

1 Like

I’d say just be smart about the implementation. Some instructions in a program must yield to previous instructions. And the programmer has control over determining which instructions don’t need to yield to others in Lua with coroutines.

Behind the scenes, there is a single Lua thread running, running one of many active coroutines at a time. The other coroutines might be in a normal or suspended state. When an HTTPRequest yields, it lets another coroutine take over.

Using coroutines, you can make several asynchronous http requests.

Here's an example of that, where a table of urls are requested asynchronously. And after all requests are performed successfully, the program then determines which has the longest response.
local http=game:GetService('HttpService')

-- Data
local urls={'https://www.lua.org/pil/7.3.html', 'https://www.google.com/search?q=chrysler+building', 'https://www.google.com/search?q=coronado'}
local responses={}

-- Request Function
function request(url, referThread)
    local response = http:GetAsync(url)
    coroutine.resume(referThread, url, response)
end

for _,url in pairs(urls) do
     coroutine.wrap(request)(url, coroutine.running()) -- Create indpenedent coroutines for all http requests to be made
end

for i=1,#urls do
    local url, response = coroutine.yield() -- Yield coroutine until next response
    responses[url] = response -- Store in table
end
-- All requests made

local longest_response_url, length = nil, 0
for url, response in pairs(responses) do -- Parse through responses to find longest one
    if #response>length then
        longest_response_url=url
        length=#response
    end
end
print(longest_response_url)
1 Like

Thank you!

I guess that explains why one of my games is not working the longer it runs (I used a lot of spawn()…)

1 Like

Here is a function that will give back a traceback during multithreading but won’t use the spawn function:

local function spawn(func, ...)
	coroutine.wrap(function(...)
		xpcall(function(...) -- xpcall now supports yielding
			func(...)
		end, function(err)
			warn(err)
			warn("Stack Begin")
			warn(debug.traceback())
			warn("Stack End")
		end, ...)
	end)(...)
end
1 Like

Thanks for the tip, but this seems more complicated than just using anyone one of run service events then disconnecting it after its fired once, but this is good to know thank you.

I think Node is probably a lot faster since it’s JIT compiled

lua is alot smaller in file size than javascript and easily beats it in speed

How is it faster?

local currentTime = DateTime.now().UnixTimestampMillis
local num = 1

for i=1,100000000 do
	num = num * 1.00001	
end

print((DateTime.now().UnixTimestampMillis)-currentTime)

2501 (ms)

“Same” code run in NodeJS:

var currentTime = Date.now();
var num = 1;

for(var i = 0; i < 100000000; i++){
    num *= 1.00001;
}

console.log(Date.now()-currentTime)

690 (ms)

oh and the javascript code is even shorter lol (lua: 173 chars, js: 138 chars)