jQuery里的$(function())为什么会改变执行顺序?

网页代码块如下:

...
<script src="./js/main.js"></script>
<script>
    try {
      window.RenderModel = {{ data|safe }};
    } catch (e) {
    }
</script>
...

后面这段内嵌代码是在页面加载是由后端(django)补全,传进来一些重要的参数。
然后,我的main.js里有这样一个变量:

var hasServer = typeof (window.RenderModel) !== 'undefined'

这个变量通过判断window.RenderModel是否存在来检测当前是否有服务器环境。
现在有一个小问题,虽然说可以解决,但是不明白其中的原理,所以请教一下各位高手。
hasServer这个变量在main.js里直接声明时,无论是否在服务器环境,window.RenderModel都被检测为undefined,因为main.js在内嵌代码前面执行,这一点是很显然的。但是,如果我将hasServer的声明放置在一个$(function())中,如这样:

$(function() {
    var hasServer = typeof (window.RenderModel) !== 'undefined'
    ...
});

这个时候hasServer就可以正常判断`window.RenderModel了,产生这种区别的原因是什么?

阅读 8.1k
2 个回答
$(function() {
    doOtherThings();
});
doSomething();

这段代码,你也许是觉得 doOtherThings() 会先执行,但实际是 doSomthing() 先执行。因为 $() 实际是 $(document).ready() 的简写,也就是说 $() 中的 functiondocument.ready 事件的回调函数。它要在 document 准备好了(加载完了)才执行。

很显示,在到达当前 HTML 最后一句之前,文档都还没准备好,而写在 $() 外面的代码,是遇到即执行。所以 doOtherThings() 是在执行 doSomehting() 之前注册到 ready 事件中,但执行却在 doSomething() 之后。

不用这么解决也行,你把下面的script标签拿到main.js上面就行,也就是写成这样:

<script>
    try {
      window.RenderModel = {{ data|safe }};
    } catch (e) {
    }
</script>
<script src="./js/main.js"></script>

为什么写在下面会是undefined呢?因为script标签你这么写是会阻塞的,也就是script标签不能并行加载,只能一个一个来(这也是为什么将script要放到后面的原因,不过可以添加async or defer),在你加载编译完main.js,你的RenderModel并没有定义,所以自然就是undefined了。
放到jq$(function(){})为什么可以?
来看下我自己实现的一个,原理和zepto相似,应该和jq也是相似的:

// callback,就是你传入的函数
ready: function (callback) {
    if (readyRE.test(document.readyState) && document.body) {
        callback();
    } else {
        document.addEventListener("DOMContentLoaded", function () {
            callback();
        }, false);
    }
    return this;
},

也就是说是在DOM构建完成,但是部分资源(image等,不包括js)还没加载完时执行函数,在这时你的window.RenderModel早早的就被定义好了,所以自然能访问到了。
同时欢迎关注下LSGO.js,基本仿照zepto.js

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题