daurnimator / lua.vm.js

The project is superceded by Fengari. See https://fengari.io/
MIT License
835 stars 101 forks source link

AJAX callbacks are firing but data is not returned #5

Closed antonh closed 10 years ago

antonh commented 11 years ago

Fantastic piece of software with a huge potential for replacing JavaScript in the browser!

A few snippets of code collected from the mailing list, wiki, issues, etc. Everything works out of the box with no perceived performance impact. I only have problems with callback return values on JQuery ajax calls and WebSockets returned message.

For example (see script_example.html below):

js.run('$.get("/glossary.json", function(data) { console.log(data); });') -- this works
jq.get("/glossary.json", function(data) print(data) end) -- the callback is firing, but data is not returned

A workaround using the load() function:

jq('#result').hide().load("/glossary.json", function() print(jq('#result').html()) end) -- this works because after the callback is fired, we just collect the result from the result div

The following goes into script_example.html:

<!-- begin script tag example -->

<script src="lua.vm.js"></script>
<script src="jquery-1.10.1.js"></script>

<!--
  Simplest web server for serving static files
  python -m SimpleHTTPServer 8080
-->

<script type="text/lua">
-- Print contents of `tbl`, with indentation.
-- `indent` sets the initial level of indentation.
function tprint (tbl, indent)
  if not indent then indent = 0 end
  for k, v in pairs(tbl) do
    formatting = string.rep("  ", indent) .. k .. ": "
    if type(v) == "table" then
      print(formatting)
      tprint(v, indent+1)
    else
      print(formatting .. tostring(v))
    end
  end
end

-- function test()
--   return 'ok'
-- end
-- for i=1,5 do
--   js.global.alert(test())
-- end

local jq = js.get("$")
-- jq('body').append("plop").click(function() js.global.alert("plop click") end)
-- local version = jq().jquery
-- js.global.alert(version)
-- jq('#result').load("/glossary.json")
jq('#result').hide().load("/glossary.json", function() print(jq('#result').html()) end)
-- jq.get("/glossary.json", function(data) print(data) end) -- callback is firing, but data is not returned
-- js.run('$.get("/glossary.json", function(data) { console.log(data); });')

-- coroutine example
-- local window = js.global
--
-- function sleep(seconds)
--   local co = coroutine.running()
--   window.setTimeout(function()
--     coroutine.resume(co)
--   end
--   , seconds * 1000)
--   coroutine.yield()
-- end
--
-- coroutine.wrap(function()
--   print("Sleeping...")
--   sleep(1)
--   print("This is the lua's coroutine")
-- end)()

-- local ws = js.new.WebSocket("ws://echo.websocket.org/?encoding=text")
-- ws.onopen = function()
--   print("connected!")
--   ws.send("Rock it with HTML5 WebSocket")
-- end
-- ws.onclose = function()
--   print("disconnected")
-- end
-- ws.onerror = function(error)
--   print(error)
-- end
-- ws.onmessage = function(e)
--   tprint(e)
--   ws.close()
-- end
</script>

<!-- end script tag example -->

<div id="result"></div>

The glossary.json file loaded in the examples above:

{
    "glossary": {
        "title": "example glossary",
        "GlossDiv": {
            "title": "S",
            "GlossList": {
                "GlossEntry": {
                    "ID": "SGML",
                    "SortAs": "SGML",
                    "GlossTerm": "Standard Generalized Markup Language",
                    "Acronym": "SGML",
                    "Abbrev": "ISO 8879:1986",
                    "GlossDef": {
                        "para": "A meta-markup language, used to create markup languages such as DocBook.",
                        "GlossSeeAlso": ["GML", "XML"]
                    },
                    "GlossSee": "markup"
                }
            }
        }
    }
}
antonh commented 11 years ago

Sorry, I just realized I forgot to come back and report the solution.

As of jQuery 1.5, all of jQuery's Ajax methods return a superset of the XMLHTTPRequest object. This jQuery XHR object, or "jqXHR," returned by $.get() implements the Promise interface, giving it all the properties, methods,...

For example, it contains responseText and responseXML properties, as well as a getResponseHeader() method.

Based on this, the following code works and returns the callback data (responseText):

local jq = js.get("$")
local jqxhr = jq.get("/glossary.json")
jqxhr.done(function() print(jqxhr.responseText) end)
greatwolf commented 11 years ago

I can't seem to do anything with the jqxhr object returned. Trying to access any of its properties results in !Unsupported! including jqxhr.done.

greatwolf commented 11 years ago

There seems to be something very odd going on with lua <--> js interaction. I'll submit this as a new issue.

Basically, this is what I'm seeing:

local jq = js.get("$")
local jqxhr = jq.get("./glossary.json")

jqxhr.done(function() print(jqxhr.responseText) end)

The above works and it prints the parsed output as expected. However, if I add some extra code using jq object then things start to mysteriously fail:

local jq = js.get("$")
local version = jq().jquery
print(version, '********')

local jqxhr = jq.get("./glossary.json")
jqxhr.done(function() print(jqxhr.responseText) end)

version of jquery gets printed but jqxhr.done will have a string value of !Unsupported!. Switching the jquery statement with jq.get will cause the reverse:

local jq = js.get("$")
local jqxhr = jq.get("./glossary.json")

local version = jq().jquery
print(version, '********')

jqxhr.done(function() print(jqxhr.responseText) end)

Now, version will contain the !Unsupported! string and jqxhr.done succeeds with the json parse.

daurnimator commented 10 years ago

Is still an issue with HEAD?

antonh commented 10 years ago

Thanks for your work! It's working now with a slightly different syntax:

<html>
  <head>
    <title>script example</title>
  </head>

  <script src="lua.vm.js"></script>
  <script src="http://code.jquery.com/jquery-latest.min.js"></script>

  <script type="text/lua">
    local jq = window.jQuery()
    print("version", jq.jquery)
    print("version second call", jq.jquery)
    local jqxhr = window.jQuery:get("/glossary.json")
    jqxhr:done(function() print(jqxhr.responseText) end)
  </script>

</html>