Coffeescript, Backbone and load order

浪子不回头ぞ 提交于 2020-01-03 18:59:32

问题


Consider this Coffeescript class, in an app where each class lives in its own file.

class Manager extends Person
  title: titles["manager"]

If that file is loaded before the "titles" object, an error generated. I'm assuming this is because of Coffeescripts safety wrapper which is performing ".call(this)" when this file is first loaded?

Otherwise, if I were to delay running any code until after the entire page had fully loaded ($(document.ready()), I could be sure that all the javascript files were fully loaded before any code actually ran.

Doesn't this create some annoying load order problems, or am I not doing something correctly?


回答1:


It can't be both an order issue and a wrapper issue. Wrapping something with a function that's run immediately has no effect on order, only on scope.

And if titles is defined in another file, then the scoping of class Manager doesn't matter. So, it's an order issue. How is titles defined?

if I were to delay running any code until after the entire page had fully loaded ($(document.ready()), I could be sure that all the javascript files were fully loaded before any code actually ran.

Not quite. $(document).ready() (note the parentheses—there is no document.ready function...) delays a function's execution until all of the page's HTML has been loaded, which doesn't mean all JavaScript has been loaded. Here's the good news: From the standpoint of JavaScript code, it doesn't matter whether other JavaScript files have been loaded, because they're all run in order. (Note: I'm assuming here that you're not doing anything fancy like adding additional <script> tags from your JavaScript code.) So as long as you have

<script src="titles.js"></script>
<script src="Manager.js"></script>

you can rest assured that Manager.js will only run after titles.js has.

Warning! Relying on $(document).ready() for ordering JS code is a common mistake that can lead to confusion! If your HTML looked like this

<script src="Manager.js"></script>
<script src="titles.js"></script>

where titles.js creates a global called titles and Manager.js looks like this

$(document).ready ->
  console.log titles

then the output will sometimes be titles, and sometimes be undefined. Why? Because as the docs say,

If .ready() is called after the DOM has been initialized, the new handler passed in will be executed immediately.

And the DOM may already have been initialized when the first JS file is run! (In practice, this will tend to happen if the browser has the page's HTML cached.)

So, keep it simple. Just load your scripts in the right order. Remember that, for all practical purposes, your scripts are concatenated together by the browser, in order, into a single JS file.




回答2:


Give a try to CoffeeToaster:
http://github.com/serpentem/coffee-toaster

It'll do exactly what you're looking for by providing import directive, which is #<<, i.e.:

#<< foldera/folderb/folderc/myfile

You don't need to inform the .coffee extension, plus you can turn on the packaging option to have namespaces facilities, if you're used to something like:

#<< another/package/myclass
class SomeClass extends another.package.MyClass

It has a build system that will output a single javascript file for you, or several (in debug mode) for easing the debugging process.

Take a look on the README and the usage example at:
https://github.com/serpentem/coffee-toaster/tree/master/usage




回答3:


It is indeed a load order problem, and titles in Manager refers to a global in this case, that isn't declared at this point. If you know titles is declared globally somewhere else, you must manually ensure that script has been loaded first. And yes, the problem may very well be with the safety wrapper. But just as a recommendation: it's there for a good reason. Create yourself a namespace instead that you export to the global object. The global object lives in this (at definition time) or exports in Node. I usually put this one-liner on top of scripts that should have easy access to the global object:

root = exports ? window

From there I can put things in the global object, like a namespace:

root.app =
  a: 1,
  a_fun: -> 1

class root.app.Cls
   method: => 1 + 1

root.app.obj = new root.app.Cls

Now, there will be an 'app' object in your global object with a 'class' (so to speak) and and object.



来源:https://stackoverflow.com/questions/7329818/coffeescript-backbone-and-load-order

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!