• jQuery 延迟对象源码


     

    Deferred延迟对象

     

    	jQuery.extend({
    
    		Deferred : function () {
    			;
    		}
    
    		when : function () {
    			;
    		}
    
    	});

    扩展了2个工具方法。
    延迟对象,是基于回调函数开发的。
    $.Deferred(); -> $.Callbacks();
    $.when();


    复习一下Callbacks:

    例子(1var cb = $.Callbacks();
        setTimeout(function () {
            alert(111);
            cb.fire();
        }, 1000);
    
    
        cb.add(function () {
            alert(222);
        })
    
        //先弹出111 ,然后是222.

     

    延迟对象Deferred

    例子(2)
    	var dfb = $.Deferred();
    	setTimeout(function () {
    		alert(111);
    		dfb.resolve();			//完成
    	}, 1000);
    
    
    	dfb.done(function () {		     //成功
    		alert(222);
    	})
    
    	//先弹出111 ,然后是222.
    

     

    如果是
    例子(3)
    	setTimeout(function () {
    		alert(111);
    	}, 1000);
    
    	alert(222);
    
    	//这就先弹出222, 在弹出111.
    
    
    如果有一个需求,就是先弹出111,再弹出222。
    如果将alert(222);放入alert(111)后面。也是一个解决办法,
    但是这样的办法,存在作用域的问题。就变成内部作用域了。
    
    这个时候选用延迟对象,就是很好的方式了。
    
    例子(4)
    	var dfb = $.Deferred();
    	setTimeout(function () {
    		alert(111);
    		dfb.reject();			//未完成
    	}, 1000);
    
    
    	dfb.fail(function () {		//失败
    		alert(222);
    	})
    
    	//先弹出111 ,然后是222.
    
    还有一个进行时:
    
    例子(5)
    	var dfb = $.Deferred();
    	setTimeout(function () {
    		alert(111);
    		dfb.notify();				//运行时
    	}, 1000);
    
    
    	dfb.progress(function () {		//动态执行
    		alert(222);
    	})
    

     


    一共三组对应:
    [ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ],
    [ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ],
    [ "notify", "progress", jQuery.Callbacks("memory") ]

    例子(6)
    $.ajax({
        url : 'xxx.php',
        success : function () {
            alert('success');
        },
        error : function () {
            alert('fail');
        }
    });
    
    
    //可以通过这个去写。成功的时候触发done,失败触发fail
    $.ajax('xxx.php').done(function () {
        alert('success');
    }).fail(function () {
        alert('fail');
    });

    resolve() 和 reject() -->>> fire()
    done() 和 fail() -->>> add()

    这个复合数组定义了对应的映射状态。
            var tuples = [
                    // action, add listener, listener list, final state
                    [ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ],
                    [ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ],
                    [ "notify", "progress", jQuery.Callbacks("memory") ]
                ],
    
        这里注意第三个:memory是有记忆功能,而once是只能触发一次。这个在callbacks中我有分析道。
    在这里的运行中,是可以多次运行的。因为无论是成功还是失败,都是已经执行结束了。而"notify", "progress"可以执行多次。
    
    数组的三个对,每一行有三个参数。最后一个是创建回调对象,完成回调方法。
    
    这里是对数组进行了匹配和分离。
        状态就是fire
        回调的方法,就是add
    源码:
        // Add list-specific methods
            jQuery.each( tuples, function( i, tuple ) {
                var list = tuple[ 2 ],            // 数组的第二项是回调对象。
                    stateString = tuple[ 3 ];    // 第三项是状态
    
                // promise[ done | fail | progress ] = list.add,
                // 这个注释阐述了回调对象的add对应着三个状态:成功,失败和进行中。这就是回调的方法。 
                promise[ tuple[1] ] = list.add;
    
                // Handle state
                if ( stateString ) {
                    list.add(function() {
                        // state = [ resolved | rejected ]
                        state = stateString;
    
                    // [ reject_list | resolve_list ].disable; progress_list.lock
                    }, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock );
                }
    
                // deferred[ resolve | reject | notify ]
                // 这个延迟对象加入了状态所对应的函数。
                // 这个状态,调用的是 fireWith 这个Callback的方法
                deferred[ tuple[0] ] = function() {
                    deferred[ tuple[0] + "With" ]( this === deferred ? promise : this, arguments );
                    return this;
                };
                deferred[ tuple[0] + "With" ] = list.fireWith;
            });
    
            // Make the deferred a promise
            promise.promise( deferred );
    
            // Call given func if any
            if ( func ) {
                func.call( deferred, deferred );
            }
    
            // All done!
            return deferred;
        },
    例子(7var dfb = $.Deferred();
        setTimeout(function () {
            alert(111);
            dfb.resolve();
        }, 1000);
    
    
        dfb.done(function () {
            alert('成功');
        }).fail(function () {
            alert('失败')
        })
    
        弹出111后。然后弹出成功。也就证明是resolve对应着done。
    如果写入reject,就对应着fail。
    
    例子(8)
        
        解释一下[ "notify", "progress", jQuery.Callbacks("memory") ]与其他两者的不同。
    
        var dfb = $.Deferred();
        setInterval(function () {
            alert(111);
            dfb.resolve();
        }, 1000);
    
    
        dfb.done(function () {
            alert('成功');
        }).fail(function () {
            alert('失败')
        })
    
        //    这里的实验结果就是第一次弹出 111, 然后弹出 ‘成功’;
        //    第二次以后只弹出 111.
    
        对比
    
        var dfb = $.Deferred();
        setInterval(function () {
            alert(111);
            dfb.notify();
        }, 1000);
    
    
        dfb.done(function () {
            alert('成功');
        }).fail(function () {
            alert('失败')
        }).progress(function () {
            alert('进行中。。');
        });
    
        //    这个就是多次弹出 111 和 进行中。。。
        //    总是成对出现。
    
    状态这个东西,只要一触发,就是结束了,没必要连续触发。
    成功就是成功了。失败就是失败了。
    
    在分析一次 memory 的问题。就是记忆功能功能。在之前的callbacks分析过了。
    这里在写一次。
    
    例子(9var cb = $.Callbacks();
        cb.add(function () {
            alert(1);
        })
        cb.fire();
    
        cb.add(function () {
            alert(2);
        })
    //这里就只能弹出    -->> 1
    
        
        var cb = $.Callbacks('memory');
        cb.add(function () {
            alert(1);
        })
        cb.fire();
    
        cb.add(function () {
            alert(2);
        })
    // 这里可以弹出 -->> 1 , 2
        在fire的时候,他有记忆功能,把所有的add添加的函数,都调用。
    
    例子(10<input type="button" value ='点击' id='but' />
    
        var cb = $.Callbacks('memory');
        cb.add(function () {
            alert(1);
        });
    
        cb.fire();
    
        var but = document.getElementById('but');
        but.onclick = function () {
            cb.add(function () {
                alert(2);
            });
        }
    
        //    这里先执行 1. 然后点击以后,执行 2,
    
    
    //这里都有memery,所以延迟对象,都有记忆功能。
    
        var dfb = $.Deferred();
        setTimeout(function () {
            alert(111);
            dfb.resolve();
        }, 1000);
    
    
        dfb.done(function () {
            alert('成功 aaa');
        });
    
        var but = document.getElementById('but');
        but.onclick = function () {
            dfb.done(function () {
                alert('bbb');
            });
        }
    
        //    先执行 111 —— >> resolve()执行,然后调用done alert('aaa')
        //    然后,点击事件的时候,立即执行 bbb。
        //    利用这个特性,就第一次不去触发执行,以后每一次都去触发执行的特性

    promise 和 deferred : 两个数组,一个定义了add ,另一个对应着firewith

       // Make the deferred a promise

      promise.promise( deferred ); //这里就是将 promise所有的方法,继承给deferred对象。
    函数执行以后。导致的结果,就是deferred比promise多出了三个方法。[resolve | reject | notify];

    例子(11function A() {
            var dfb = $.Deferred();
            setTimeout(function () {
                alert(111);
                dfb.resolve();
            }, 1000);
    
            return dfb;
        }
    
        var df = A();
    
        df.done(function () {
            alert('成功 aaa');
        }).fail(function () {
            alert('fail bbb');
        });
    
        df.reject();
    
        //    执行结果,先执行失败,fail bbb
        //    在执行111
        //     原因是,因为 df.reject(); 先执行,而后,直接就执行了fail, 1秒钟以后,才执行了计时函数,
    
    那如何让外面不能修改呢?
        很简单,promise。(这个属性已经在ES6中有独立出来了,就是解决回调问题的。)
        
        function A() {
            var dfb = $.Deferred();
            setTimeout(function () {
                alert(111);
                dfb.resolve();
            }, 1000);
    
            return dfb.promise();    //这里加上了promise,就变成promise对象。
            //    注意啊,promise    是没有    [resolve | reject | notify] 这三个方法的,
            //    所以,根本无法改变状态。
            //    没有参数,就返回promise对象了。
        }
    
        var df = A();
    
        df.done(function () {
            alert('成功 aaa');
        }).fail(function () {
            alert('fail bbb');
        });
    
        df.reject();    //这里报错,找不到这个函数。肯定找不到啊。因为promise没有这个函数。
    
        //    执行结果,这回就是返回成功和111.并且,reject还会报错。
        //    因为用了promise之后,就不能再进行修改状态了。
    
    
    
    例子(12)
        查看状态:obj.state();
        并传入参数
    
        function A() {
            var df = $.Deferred();
            alert (df.state());        //pending
    
            setTimeout(function () {
                alert(111);
                df.resolve('hg');    //传入参数
            }, 1000);
    
            return df.promise();    //这里加上了promise
        }
    
        var df = A();
    
        df.done(function () {
            alert('成功 aaa');
            alert(arguments[0]);    //可以获取传入的参数
            alert (df.state());        //resolve
    
        }).fail(function () {
            alert('fail bbb');
            alert (df.state());
        });
    
    
    源码:
        // Handle state
        if ( stateString ) {
            list.add(function() {
                // state = [ resolved | rejected ]
                state = stateString;
    
            // [ reject_list | resolve_list ].disable; progress_list.lock
            //    这里就是三选一,选择了一个,另外两个状态就不会触发。 ^ 是位运算符。
            }, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock );
        }
    
    
    例子(13var df = $.Deferred();
    
        setTimeout(function () {
            df.resolve('hg');
    
        }, 1000);
    
        var newDf = df.pipe(function () {
            return arguments[0] + " wj";
        });
    
        newDf.done(function () {
            alert(arguments[0]);
        });
    
        //    打印出 hg wj
        //    pipe的返回值,作为新的状态转移的参数。返回一个新的不能修改状态的延迟对象。
        //     pipe不影响状态,只是影响参数。
    总结一下:
        promise。缺少三种状态,只要延迟对象调用promise()方法,就是不能修改状态了。
    
        promise {
            //方法。
            state     :    状态。
                有state()的方法,获取状态
    
            always    :     总是触发,不管是你完成,还是未完成,都是触发。
                    always: function() {
                        deferred.done( arguments ).fail( arguments );
                        return this;
                    },
    
            then    :  /* fnDone, fnFail, fnProgress */  分开写。
                    obj,then(function () {
                        //fnDone
                    }, function () {
                        //fnFail
                    },function () {
                        //fnProgress
                    });    
    
            promise        //如果有参数,就将promise下面的所有方法,都继承给obj对象。
                        promise: function( obj ) {
                            return obj != null ? jQuery.extend( obj, promise ) : promise;
                        }
    
            pipe    :    管道,给参数做个处理。并不影响状态转移。
                        可以理解为继承的延迟对象。
                        // Keep pipe for back-compat
                        promise.pipe = promise.then;
    
            done | fail | progress;
        }
    
    
        deferred {
            //方法
            resolve | reject | notify + promise对象内的属性和方法。
    }

     

  • 相关阅读:
    ajax请求默认都是异步请求,怎么变为同步请求
    TP6跨域问题
    localStorage使用总结
    win10 windows management instrumentation cpu占用高解决方法
    限制性股票-股份支付
    可转债会计分类
    其他权益工具投资的交易费用计入成本
    年数总和法
    外币货币性项目汇兑差额应当计入当期损益
    chrome怎么设置点击窗口在新窗口打开
  • 原文地址:https://www.cnblogs.com/hgonlywj/p/4858151.html
Copyright © 2020-2023  润新知