时序问题在javascript中比较常见,尤其是在网络环境不稳定时以及某些浏览器本来版本中比较多,遇到此类问题,往往会使开发者非常头痛,问题的重现需要特定的环境,是偶发的,不容易重现。对于有经验的开发者,大部分的时序问题都可以在代码中避免,对于浏览器,js代码的执行是单线程的,同一时刻只有一段js代码在执行,js的执行主要是通过两种方式来触发:

  1. script标签中的代码加载执行:js是解释型语言,从上到下边解释边执行,通常,在模块化的js代码中,我们一般习惯给与一个统一的初始化执行入口。
  2. 通过事件分发的形式来执行:如按钮点击,鼠标划过等事件触发,主要对应于用户操作dom节点触发,当然,ajax请求回调也属于事件分发形式。

我们看以下代码片段。

代码1:

<script type="text/javascript">var str = "hello, world";
</script>
<script type="text/javascript">str = "I was re-defined";
</script>

代码2:

<script type="text/javascript">var ClassB = {hello : function(){alert(str);}};ClassB.hello();
</script>

毫无悬念,这样的执行是没有问题的,此处是第一种触发方式,代码1执行的时候,str已经声明并赋值完毕,如果反过来就是undefind。

再看如下两段代码:

代码1:

<script type="text/javascript">var str = "hello, world";YUI().use('io', function(Y){str = "I was re-defined";});
</script>

代码2:

<script type="text/javascript">YUI().use('node', function(Y){var ClassB = {hello : function(){alert(str);}};ClassB.hello();
});
</script>

我们首先想到的应该是弹出的“I was re-defined”,因为str被重定义了, 其实不然,use里的模块不一样,执行alert出来的结果都是不同的。在解释这个问题之前,我们先来分析一下YUI3的加载方式:

YUI3采用分模块按需加载的方式来加载自己的组件,我们使用时只需要将所需使用的模块放到use中,自己代码則是放在一个闭包里面,全局Y对象作为一个参数传过来,就如上面一段代码。这样做的好处是因为YUI组件库本身比较庞大,而我们平时使用时很多功能是用不到的,全部加载显然耗时耗流量,按需动态加载則完美的解决了这个问题。

1. 首先需要引入YUI3的一个基础文件:

<script type="text/javascript" src="http://yui.yahooapis.com/3.2.0/build/yui/yui-min.js"></script>

该文件中定义了一些全局变量,use方法,组件的配置文件的路径(loader-min.js),use执行完成后的回调等,以供后续使用,代码如下图

yui-min中的init方式定义了loaderPath即组件文件的路径,在我们没有使用use方法时,所有的组件都不会加载进来的,就仅仅只有一个yui-min.js文件而已。

2. 我们使用YUI().use('node', function(Y){})方法(该方法在yui-min.js中定义),触发Y.Get.script方法,此时就会加载loader-min.js:

该文件里定义了所有的组件(包括YUI3自带的组件以及用户自定义组件)的名称,依赖模块,路径等,use中使用的所有模块都应该在该文件中有定义,配置如下所示:

3. 根据use中声明的所要加载的模块,结合loader中的模块定义,有依赖模块的将依赖模块也加进来,依赖模块同时也有依赖模块,以此类推,将所有模块都加进来,然后向服务器发送请求,加载请求模块。

4. 请求模块加载完成以后执行回调,执行function(Y){}里面的内容。

整个加载过程的抓包数据如下:

此处是以3.2.0版本为例来说明,在YUI3的新版中将loader-min.js并到了yui-min.js中,可以减少一个请求,anyway,总的流程变化不大。

继续回到我们上面讨论的问题,这里片段2的执行采用的事件驱动触发方式,第一段代码片段和第二段代码片段还是会被浏览器按照从上到下的方式依次解释,此时,YUI整个组件库并没有被下载下来,只是加载了一个配置文件而已。两个代码片段各自获得其所需要加载的模块组件并向服务器发送请求,两个代码片段所需yui模块加载完成的速度是不确定的,从而导致出现上述情况。

这个也是YUI3设计的一个初衷,各个功能块都在各自的闭包里面,彼此独立,互不干扰,这也是模块化的一个目标。在实际应用中,要尽量避免出现上述情况,根据实际情况区分对待:

  1. 最简单的方式,把代码1与代码2写在同一个use闭包中,这样就不会有问题。
  2. 代码1在很多场景都会使用,每个js文件中重复定义可维护性会降低。此时,可以将代码1作为一个单独的组件封装起来。有些人会觉得这样代码1虽然有公用性,但也不是很强,封装起来有些浪费,其实按照按需加载的逻辑,作为YUI3的一个组件封装起来并不会使整体的代码非常冗余。
  3. 如果实在不能写在一个use闭包中,也觉得完全没必要封装,这个时候就采用比较笨重的方法,在代码2中设置一个定时器来跑吧(有人说如果代码1中有错误会导致代码2无法执行,好吧,如果代码1中有错误,你用什么方法都避免不了)。

这种情况发生发代码2的初始化方法函数调用代码1中的方法时会发生,如果代码2中事件事件分发执行的函数(如用户点击事件等,ajax回调)去调用代码1中的方法一般不会有这样的问题,当然,并不是100%不会发生…

转载于:https://www.cnblogs.com/v-rockyli/p/3637964.html

【原】YUI3:js加载过程及时序问题相关推荐

  1. html动态资源加载进度,JavaScript_快速解决js动态改变dom元素属性后页面及时渲染的问题,今天实现一个进度条加载过程 - phpStudy...

    快速解决js动态改变dom元素属性后页面及时渲染的问题 今天实现一个进度条加载过程,dom结构其实就是两个div 控制里层div的宽width属性,就能实现进度条往前走的效果. 我的进度条是显示下载文 ...

  2. 前端资源(css,js,图片,接口等)加载过程

    查看前端各资源css,js,图片,接口等加载速度 前言 查看前端各资源加载速度 加载过程中各指标详解 前言 网页打开的速度快慢直接影响了用户体验.据统计,Google网站访问速度每慢400ms就导致用 ...

  3. python爬取js加载的数据_Python爬虫学习,记一次抓包获取js,从js函数中取数据的过程...

    昨天有小伙伴找我,新浪新闻的国内新闻页,其他部分都是静态网页可以抓到,但是在左下方的最新新闻部分,不是静态网页,也没有json数据,让我帮忙抓一下.大概看了下,是js加载的,而且数据在js函数中,很有 ...

  4. 模块加载过程代码分析1

    一.概述 模块是作为ELF对象文件存放在文件系统中的,并通过执行insmod程序链接到内核中.对于每个模块,系统都要分配一个包含以下数据结构的内存区. 一个module对象,表示模块名的一个以null ...

  5. 优化JS加载时间过长的一种思路

    文章版权由作者李晓晖和博客园共有,若转载请于明显处标明出处:http://www.cnblogs.com/naaoveGIS/. 1.背景 去年公司在漳州的一个项目中,现场工程人员反映地图部分出图有点 ...

  6. [f]动态判断js加载完成

    在正常的加载过程中,js文件的加载是同步的,也就是说在js加载的过程中,浏览器会阻塞接下来的内容的解析.这时候,动态加载便显得尤为重要了,由于它是异步加载,因此,它可以在后台自动下载,并不会妨碍其它内 ...

  7. 关于前端性能优化问题,认识网页加载过程和防抖节流

    前端性能优化-网页加载过程.性能优化方法.防抖和节流 一.网页加载过程 1.加载资源的形式 2.加载资源的过程 3.渲染页面的过程 4.关于window.onload 和 DOMContentLoad ...

  8. three.js加载3d模型_基于WebGL的3D技术在网页中的运用 ThingJS 前端开发

    Three.js.ThingJS这些引擎库可以加载3D制作软件的模型,大幅度提高了制作效率,改变WebGL开发困难的局面,让Web开发者享受便捷的3D开发服务.三者的难度对比如下: ThingJS(框 ...

  9. linux内核启动以及文件系统的加载过程

    Linux 内核启动及文件系统加载过程 当u-boot 开始执行 bootcmd 命令,就进入 Linux 内核启动阶段.普通 Linux 内核的启动过程也可以分为两个阶段.本文以项目中使用的 lin ...

  10. vue使用three.js加载.FBX模型文件

    1.需要安装的依赖 //three依赖yarn add three//tween.js依赖yarn add @tweenjs/tween.js 2. 封装组件 draw.vue 放在component ...

最新文章

  1. Spark 报错 DROP TABLE IF EXISTS should not show AnalysisException
  2. 如何解决设置虚拟服务器不生效,nginx虚拟主机的配置不生效
  3. 【2019.09.01】2019南京网络赛
  4. python 享元模式_设计模式-创建型模式,python享元模式 、python单例模式(7)
  5. activiti 流程文件存哪里_JAVA-工作流引擎-activiti-Tasks介绍
  6. malware analysis、Sandbox Principles、Design Implementation
  7. 机器学习中性能评估指标中的准确率(Accuracy)、召回率(Recall=TPR)、精确率(Precision)、误报率(FPR)、漏报率(FNR)及其关系
  8. 能源DEA--对于业务和环境评估的规模报酬与规模损害
  9. 怎么测试ftp服务器上传文件,ftp服务器文件上传测试
  10. XILINX SGMII千兆以太网 (2)
  11. 使用breakpad收集native奔溃日志及dump解析
  12. 2014校园招聘_百度2014校园招聘
  13. 该怎么职场中进行有效沟通工作?
  14. 认证考试:操作系统安全稳定的电脑使用方法!
  15. 东北大学材料成型工艺学中挤压拉拔部分复习
  16. 百度语音合成(TTS) 在Android的使用方法
  17. Outlook Express常见问答
  18. FunHouse-F10-MPro-1005G1-Hackintosh-Opencore 黑苹果efi引导文件
  19. 基于OpenCV的棋盘图像识别
  20. iyiw oracle_oracle详解

热门文章

  1. 数字化建筑与数字化建造,数字化建筑设计与建造
  2. 【码学堂】教师如何在码学堂上组织教学活动?
  3. 药理学(综合练习)题库【1】
  4. ADC0808确定地址及查询方式示例
  5. 你们刚开始是怎么看英文文献的?
  6. Leetcode——C++突击面试
  7. 基于SSM+VUE游戏账号交易系统
  8. 在线Cron表达生成器(定时任务时间控制)
  9. Eclipse中文版之完美汉化教程(详细图解)
  10. 常用javascript编码规范