延时调用--deferred.js原码分析
有些时候,我们需要等待上一个操作完成之后,才能进行下一步的操作。比如Ajax实现自动提交表单操作的时候,程序需要等待,一旦有返回结果了,则继续进行一下步操作。
这时deferred.js这个库就产生了,当然,jquery也有这个功能。下面就分析一下这个库的原理:
- /**
- * @fileOverview JSDeferred
- * @author cho45@lowreal.net
- * @version 0.4.0
- * @license
- * JSDeferred Copyright (c) 2007 cho45 ( www.lowreal.net )
- *
- * 针对deferred的原理进行精简
- */ ; // no warnings for uglify
- function Deferred () {
- return this.init();
- }
- //定义静态方法
- Deferred.ok = function(x) {return x} //缺省的成功回调
- Deferred.ng = function(x) {throw x}
- //判断是否为Deferred的实例
- Deferred.isDeferred = function (obj) {
- return !!(obj && obj._id === Deferred.prototype._id);
- };
- //这个next是挂在Deferred上的静态方法。与实列方法.next是不同的
- Deferred.next = function(fn){
- var d = new Deferred();
- var img = new Image();
- var handler = function(){
- d.canceller();
- d.calls();
- }
- //这个地方个人认为比较巧秒,它利用了img加载成功或错误回调具有异步的特性。
- //保证完整收集这些.next().next()...
- //事实上官方还用了其它两种方式,确保兼容,如setTimeout....
- img.addEventListener('error',handler,false);
- d.canceller = function(){
- img.removeEventListener('error',handler,false);
- }
- //这里用来触发一个img的加载事件
- img.src = "data:image/png," + Math.random();
- if(fn) d.callback.ok = fn;
- return d;
- }
- //这里是用来模拟一个比较耗时的异步过程
- //实践中,可能是取数据的过程,如等待ajax回调
- Deferred.wait = function (n) {
- var d = new Deferred(), t = new Date();
- var id = setTimeout(function () {
- d.calls((new Date()).getTime() - t.getTime());
- }, n * 1000);
- d.canceller = function () { clearTimeout(id) };
- return d;
- };
- Deferred.prototype = {
- _id : 8888, //随便填写,用来判断是否为Deferred的实例
- init : function(){
- this._next = null;
- //使Deferred.isDeferred 判断为假
- this.callback = {
- ok : Deferred.ok,
- ng : Deferred.ng
- }
- return this;
- },
- next : function (fun) { return this._post("ok", fun) },
- calls : function (val) { return this._fire("ok", val) },
- _post : function (okng, fun) {
- //个人认为,理解这里是关键,
- //._next保存一下实例对象,形成一个链
- this._next = new Deferred();
- this._next.callback[okng] = fun;
- return this._next;
- },
- _fire : function (okng, value) {
- var next = "ok";
- value = this.callback[okng](value);
- //这里的value如果不是Deferred的实例
- if (Deferred.isDeferred(value)) {
- //加载下一个任务
- value._next = this._next;
- } else {
- //说明没有下一个任务了
- if (this._next) this._next._fire(next, value);
- }
- return this;
- }
- }
为了配合分析,先给一段测试代码,方便追踪它的流程。
- Deferred.next(function(){
- alert(1)
- return Deferred.wait(3)
- }).next(function(){
- alert(2)
- })
这里用了一个链式写法,熟jquery的人,对此一定不会陌生。首先是调用Deferred.next()这个方法,返回一个Deferred的实例,然后调用实例上的next()方法。
意图是要执行第一个函数(弹出1)之后,再执行第二函数(弹出2),仅管在写法是同步的,但是执行的时候却是异步的。 你或许会问, 为什么不直接用setTimeout呢?
这个问题非常好,其实在很情况下,我觉得确实是可以等价交换。但是setTimeout有一个使用前提,那就是我们必需事先知道上一步运行完成需要等多长时间。而Deferred不需要。
这时你或许又会问,那为什么不用回调呢?这回我终于没有办法说什么了。直接演示一下这种写法:
- function(next1,next2,next3,...){
- //....
- //....
- next1(function(){
- next2(function(){
- next3(...);
- })
- })
- }
像竹笋一样,一层套一层。如果函数体长一点,看着不晕吗?再看看deferred的写法:
- Deferred.next(function(){
- next1();
- }).next(function(){
- next2();
- }).next(function(){
- next3()
- }).next(function(){
- //...
- })
像麻将一样,一字排开,是时髦的链式用法。
如果你觉得怎么写无所谓,那么要结合起来看了,如果next1是一个耗时不确定的操作,但是要保证执行顺序。怎么破?
不管你怎么破,反正我是选择Deferred,用定了。
延时调用--deferred.js原码分析的更多相关文章
- basket.js 源码分析
basket.js 源码分析 一.前言 basket.js 可以用来加载js脚本并且保存到 LocalStorage 上,使我们可以更加精准地控制缓存,即使是在 http 缓存过期之后也可以使用.因此 ...
- jqGrid pivot获取所有行包括小计数据及原码分析
1.结论:按正常jqGid获取,在中间加入以下代码,即将小计行当成改变为普能行,以便能让'getRowData'方法获取到,第三点会进行原码分析 //get all page grid data,in ...
- events.js 源码分析
events.js 源码分析 1. 初始化 // 使用 this.ee = new EventEmitter(); // 源码 // 绑定this域,初始化 _events,_eventsCount和 ...
- Require.js 源码分析
本文将简单介绍下个人对require.js的源码分析,简单分析实现原理 一.require加载资源的流程 require中,根据AMD(Asynchronous Module Definition)的 ...
- Backbone.js源码分析(珍藏版)
源码分析珍藏,方便下次阅读! // Backbone.js 0.9.2 // (c) 2010-2012 Jeremy Ashkenas, DocumentCloud Inc. // Backbone ...
- Vue.js 源码分析(三十一) 高级应用 keep-alive 组件 详解
当使用is特性切换不同的组件时,每次都会重新生成组件Vue实例并生成对应的VNode进行渲染,这样是比较花费性能的,而且切换重新显示时数据又会初始化,例如: <!DOCTYPE html> ...
- Vue.js 源码分析(三十) 高级应用 函数式组件 详解
函数式组件比较特殊,也非常的灵活,它可以根据传入该组件的内容动态的渲染成任意想要的节点,在一些比较复杂的高级组件里用到,比如Vue-router里的<router-view>组件就是一个函 ...
- Vue.js 源码分析(二十九) 高级应用 transition-group组件 详解
对于过度动画如果要同时渲染整个列表时,可以使用transition-group组件. transition-group组件的props和transition组件类似,不同点是transition-gr ...
- Vue.js 源码分析(二十八) 高级应用 transition组件 详解
transition组件可以给任何元素和组件添加进入/离开过渡,但只能给单个组件实行过渡效果(多个元素可以用transition-group组件,下一节再讲),调用该内置组件时,可以传入如下特性: n ...
随机推荐
- Log4j按级别输出到不同文件
log4j.properties 文件: log4j.logger.net.sf.hibernate.cache=debug log4j.rootLogger = error,portal_log,s ...
- (转)win7 64 安装mysql-python:_mysql.c(42) : fatal error C1083: Cannot open include file: 'config-win.h': No such file or directory
原文地址:http://www.cnblogs.com/fnng/p/4115607.html 作者:虫师 今天想在在win7 64位环境下使用python 操作mysql 在安装MySQL-pyth ...
- 日常关键字:定时关机、该任务映像已损坏或已篡改.(0x80041321)、ChaZD生词同步扇贝
我在床上用chinanet网络慢得简直令人发指,12B/S.是的你没有看错,这是我最常看到的网速.但是我最近发现电脑联网开出一个WiFi,在床上用手机上网时,网速会一点提升,可达到1KB/S(⊙﹏⊙) ...
- Python之路第一课Day8--随堂笔记(socket 承接上节---网络编程)
本节内容 Socket介绍 Socket参数介绍 基本Socket实例 Socket实现多连接处理 通过Socket实现简单SSH 通过Socket实现文件传送 作业:开发一个支持多用户在线的FTP程 ...
- nginx超时重发
最近一直遇到一个bug: 客户端会二次请求服务端,服务端多次调用remote服务. 特点是,这些请求都是模型切片相关的,耗时很长的请求,往往需要1分钟左右. 开始以为是客户端代码有问题,进行了二次请求 ...
- 自写函数VB6 STUFF函数 和 VB.net 2010 STUFF函数 详解
'*************************************************************************'**模 块 名:自写函数VB6 STUFF函数 和 ...
- HTML基础篇之知识点补充和拓展
<tbody>标签 <tbody>如果表格内容非常多的时候,如果加上这个标签它会让这个表格全部下载好才会显示.用在表格标签上面. 如果您使用 thead.tfoot 以及 tb ...
- 下载判断Android和iOS
//下载 function down(){ var url = ''; var u = navigator.userAgent, app = navigator.appVersion; var isA ...
- C# DataSet
一.基本概念 DataSet是ADO.NET的中心概念.可以把DataSet当成内存中的数据库,DataSet是不依赖于数据库的独立数据集合.所谓独立,就是说,即使断开数据链路,或者关闭数据库,Dat ...
- Android图片资源
title: 2016-5-5未命名文件 tags: UI适配,图片资源 grammar_cjkRuby: true --- 概述: 本文整理了Android开发中,图片资源的提供方式和使用方式.包括 ...