目錄
jQuery.when方法
后续
首頁 web前端 js教程 jQuery原始碼解析Deferred非同步物件的方法

jQuery原始碼解析Deferred非同步物件的方法

Oct 26, 2017 am 10:21 AM
jquery 非同步

在工作中我們可能會把jQuery選擇做自己專案的基礎函式庫,因為其提供了簡單的DOM選擇器以及封裝了很多實用的方法,例如$.ajax(),它使得我們不用操作xhrxdr對象,直接書寫我們的程式碼邏輯即可。更豐富的是它在ES6沒有原生支援的那段時間,提供了Deferred對象,類似於Promise對象,支援done/ fail/progress/always方法和when批次方法,這可能在專案上幫助過你。

ES6提供了Promise對象,但由於它是內建C++實現的,所以你也沒辦法看它的設計。不如我們透過jQuery的原始碼來探究其設計思路,​​並比較一下兩者的差異。本文採用jquey-3.1.2.js版本,其中英文註解為原版,中文註解為我新增。

jQueryajax整體設計

#jQuery在內部設定了全域的ajax參數,在每一個ajax請求初始化時,用傳遞的參數與預設的全域參數進行混合,並建構一個jqXHR物件(提供比原生XHR更為豐富的方法,同時實現其原生方法),透過傳遞的參數,來判斷其是否跨域、傳遞的參數類型等,設定好相關頭部資訊。同時其被初始化為一個內建Deferred物件用於非同步操作(後面講到),並添加done/fail方法作為回調。同時我們也封裝了$.get/$.post方法來快速呼叫$.ajax方法。

上面提到的Deferred對象,與ES6的Promise物件類似,用於更為方便的非同步操作,多種回呼以及更好的書寫方式。提供progress/fail/done方法,並分別用該物件的notify/reject/resolve方法觸發,可以使用then方法快速設定三個方法,使用always新增都會執行的回調,並且提供when方法支援多個非同步操作合併回調。可以追加不同的回呼列表,其回呼列表是使用內部Callbacks對象,更方便的按照隊列的方式來執行。

Callbacks回呼佇列對象,用於建立易於操作的回呼函數集合,在操作完成後進行執行。支援四種初始化的方式once/unique/memory/stopOnFalse,分別代表只執行依序、去重、快取結果、鍊式呼叫支援終止。提供fired/locked/disabled狀態值,代表是否執行過、鎖定、停用。提供add/remove/empty/fire/lock/disable方法操作回呼函數佇列。

主要涉及的概念就是這三個,不再做延伸,三個物件的設計程式碼行數在1200行左右,斷斷續續看了我一週(´ཀ`」 ∠) 。我們從這三個倒序開始入手剖析其設計。

jQuery.Callbacks物件

Callbacks對象,用於管理回呼函數的多用途清單。它提供了六個主要方法:

  1. add: 在清單中新增回呼函數

  2. remove : 移除清單中的回呼函數

  3. empty: 清空清單中的回呼函數

  1. #fire
  2. : 依序執行清單中的回呼函數

  3. lock
  4. : 對清單上鎖,禁止一切操作,清除數據,但保留快取的環境變數(只在

    memory參數時有用)

  5. #disable: 停用該回呼列表,所有資料都清空

    #在初始化時,支援四個參數,用空格分割:

#once: 此回呼清單只執行依序

memory: 快取執行環境,在新增回呼時執行先執行一次

unique: 去重,每一個函數皆不同(指的是引用位址)stopOnFalse

: 在呼叫中,如果前一個函數回傳
    false
  1. ,中斷清單的後續執行

    我們來看下其實例使用:###
    let cl = $.Callbacks('once memory unique stopOnFalse');
    fn1 = function (data) {
        console.log(data);
    };
    fn2 = function (data) {
        console.log('fn2 say:', data);
        return false;
    };
    cl.add(fn1);
    cl.fire('Nicholas');    // Nicholas
    // 由于我们使用memory参数,保存了执行环境,在添加新的函数时自动执行一次
    cl.add(fn2);    // fn2 say: Nicholas
    // 由于我们使用once参数,所以只能执行(fire)一次,此处无任何输出
    cl.fire('Lee');
    
    // 后面我们假设这里没有传入once参数,每次fire都可以执行
    
    cl.fire('Lee');    // Lee    fn2 say: Lee
    // 清空列表
    cl.empty();
    cl.add(fn2, fn1);
    // 由于我们设置了stopOnFalse,而fn2返回了false,则后添加的fn1不会执行
    cl.fire('Nicholas');    // fn2 say: Nicholas
    // 上锁cl,禁用其操作,清除数据,但是我们添加了memory参数,它依然会对后续添加的执行一次
    cl.lock();
    // 无响应
    cl.fire();
    cl.add(fn2);    // fn2 say: Nicholas
    // 禁用cl,禁止一切操作,清除数据
    cl.disable();
    登入後複製
    ###除了上面所說的主要功能,還提供###has/locked/disabled /fireWith/fired###等輔助函數。 ######其所有原始碼實作及註解為:###
    jQuery.Callbacks = function( options ) {
        options = typeof options === "string" ?
            // 将字符串中空格分割的子串,转换为值全为true的对象属性
            createOptions( options ) :
            jQuery.extend( {}, options );
    
        var // Flag to know if list is currently firing
            firing,
    
            // Last fire value for non-forgettable lists
            memory,
    
            // Flag to know if list was already fired
            fired,
    
            // Flag to prevent firing
            locked,
    
            // Actual callback list
            list = [],
    
            // Queue of execution data for repeatable lists
            queue = [],
    
            // Index of currently firing callback (modified by add/remove as needed)
            firingIndex = -1,
    
            // Fire callbacks
            fire = function() {
    
                // Enforce single-firing
                locked = locked || options.once;
    
                // Execute callbacks for all pending executions,
                // respecting firingIndex overrides and runtime changes
                fired = firing = true;
                // 为quene队列中不同的[context, args]执行list回调列表,执行过程中会判断stopOnFalse中间中断
                for ( ; queue.length; firingIndex = -1 ) {
                    memory = queue.shift();
                    while ( ++firingIndex < list.length ) {
    
                        // Run callback and check for early termination
                        if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false &&
                            options.stopOnFalse ) {
    
                            // Jump to end and forget the data so .add doesn&#39;t re-fire
                            firingIndex = list.length;
                            memory = false;
                        }
                    }
                }
    
                // Forget the data if we&#39;re done with it
                if ( !options.memory ) {
                    memory = false;
                }
    
                firing = false;
    
                // Clean up if we&#39;re done firing for good
                // 如果不再执行了,就将保存回调的list清空,对内存更好
                if ( locked ) {
    
                    // Keep an empty list if we have data for future add calls
                    if ( memory ) {
                        list = [];
    
                    // Otherwise, this object is spent
                    } else {
                        list = "";
                    }
                }
            },
    
            // Actual Callbacks object
            self = {
    
                // Add a callback or a collection of callbacks to the list
                add: function() {
                    if ( list ) {
    
                        // If we have memory from a past run, we should fire after adding
                        // 如果我们选择缓存执行环境,会在新添加回调时执行一次保存的环境
                        if ( memory && !firing ) {
                            firingIndex = list.length - 1;
                            queue.push( memory );
                        }
    
                        ( function add( args ) {
                            jQuery.each( args, function( _, arg ) {
                                // 如果是函数,则判断是否去重,如果为类数组,则递归执行该内部函数
                                if ( jQuery.isFunction( arg ) ) {
                                    if ( !options.unique || !self.has( arg ) ) {
                                        list.push( arg );
                                    }
                                } else if ( arg && arg.length && jQuery.type( arg ) !== "string" ) {
    
                                    // Inspect recursively
                                    add( arg );
                                }
                            } );
                        } )( arguments );
    
                        if ( memory && !firing ) {
                            fire();
                        }
                    }
                    return this;
                },
    
                // Remove a callback from the list
                // 移除所有的相同回调,并同步将firingIndex-1
                remove: function() {
                    jQuery.each( arguments, function( _, arg ) {
                        var index;
                        while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {
                            list.splice( index, 1 );
    
                            // Handle firing indexes
                            if ( index <= firingIndex ) {
                                firingIndex--;
                            }
                        }
                    } );
                    return this;
                },
    
                // Check if a given callback is in the list.
                // If no argument is given, return whether or not list has callbacks attached.
                // 检查是否存在该函数,如果不传递参数,则返回是否有回调函数
                has: function( fn ) {
                    return fn ?
                        jQuery.inArray( fn, list ) > -1 :
                        list.length > 0;
                },
    
                // Remove all callbacks from the list
                empty: function() {
                    if ( list ) {
                        list = [];
                    }
                    return this;
                },
    
                // Disable .fire and .add
                // Abort any current/pending executions
                // Clear all callbacks and values
                // 置locked为[],即!![] === true,同时将队列和列表都清空,即禁用了该回调集合
                disable: function() {
                    locked = queue = [];
                    list = memory = "";
                    return this;
                },
                disabled: function() {
                    return !list;
                },
    
                // Disable .fire
                // Also disable .add unless we have memory (since it would have no effect)
                // Abort any pending executions
                // 不允许执行,但如果有缓存,则我们允许添加后在缓存的环境下执行新添加的回调
                lock: function() {
                    locked = queue = [];
                    if ( !memory && !firing ) {
                        list = memory = "";
                    }
                    return this;
                },
                locked: function() {
                    return !!locked;
                },
    
                // Call all callbacks with the given context and arguments
                // 为fire附带了一个上下文来调用fire函数,
                fireWith: function( context, args ) {
                    if ( !locked ) {
                        args = args || [];
                        args = [ context, args.slice ? args.slice() : args ];
                        queue.push( args );
                        if ( !firing ) {
                            fire();
                        }
                    }
                    return this;
                },
    
                // Call all the callbacks with the given arguments
                fire: function() {
                    self.fireWith( this, arguments );
                    return this;
                },
    
                // To know if the callbacks have already been called at least once
                fired: function() {
                    return !!fired;
                }
            };
    
        return self;
    };
    登入後複製
    ######jQuery.Deferred###物件#########jQuery.Deferred###物件是一個工廠函數,傳回一個用於非同步或同步呼叫的###deferred###對象,支援鍊式呼叫、回呼函數佇列,並且能針對返回的狀態不同執行不同的回呼。它類似於###ES6###提供的###Promise###對象,提供9個主要的方法:##############done###: 操作成功響應時的回呼函數(同步或非同步,以下相同)###
  2. fail: 操作失败响应时的回调函数

  3. progress: 操作处理过程中的回调函数

  4. resolve: 通过该方法解析该操作为成功状态,调用done

  5. reject: 通过该方法解析该操作为失败状态,调用fail

  6. notify: 通过该方法解析该操作为执行过程中,调用progress

  7. then: 设置回调的简写,接收三个参数,分别是done/fail/progress

  8. always: 设置必须执行的回调,无论是done还是fail

  9. promise: 返回一个受限制的Deferred对象,不允许外部直接改变完成状态

它的实现思想是创建一个对象,包含不同状态下回调函数的队列,并在状态为失败或成功后不允许再次改变。通过返回的Deferred对象进行手动调用resolve/reject/notify方法来控制流程。

看一个实例(纯属胡扯,不要当真)。我们需要从间谍卫星返回的数据用不同的算法来进行解析,如果解析结果信号强度大于90%,则证明该数据有效,可以被解析;如果强度小于10%,则证明只是宇宙噪音;否则,证明数据可能有效,换一种算法解析:

// 我们封装Deferred产生一个promise对象,其不能被外部手动解析,只能内部确定最终状态
asynPromise = function () {
    let d = $.Deferred();
    (function timer() {
        setTimeout(function () {
            // 产生随机数,代替解析结果,来确定本次的状态
            let num = Math.random();
            if (num > 0.9) {
                d.resolve();    // 解析成功
            } else if (num < 0.1) {
                d.reject();    // 解析失败
            } else {
                d.notify();    // 解析过程中
            }
            setTimeout(timer, 1000);    // 持续不断的解析数据
        }, 1000);
    })();
    // 如果不返回promise对象,则可以被外部手动调整解析状态
    return d.promise();
};

// then方法的三个参数分别代表完成、失败、过程中的回调函数
asynPromise().then(function () {
    console.log(&#39;resolve success&#39;);
}, function () {
    console.log(&#39;reject fail&#39;);
}, function () {
    console.log(&#39;notify progress&#39;);
});

// 本地执行结果(每个人的不一样,随机分布,但最后一个一定是success或fail)
notify progress
notify progress
notify progress
notify progress
notify progress
reject fail    // 后面不会再有输出,因为一旦解析状态为success或fail,则不会再改变
登入後複製

除了上面的主要功能,还提供了notifyWith/resolveWith/rejectWith/state辅助方法。

其所有的源码实现和注释为:

Deferred: function( func ) {
        var tuples = [
                // action, add listener, callbacks,
                // ... .then handlers, argument index, [final state]
                // 用于后面进行第一个参数绑定调用第二个参数,第三个和第四个参数分别是其不同的回调函数队列
                [ "notify", "progress", jQuery.Callbacks( "memory" ),
                    jQuery.Callbacks( "memory" ), 2 ],
                [ "resolve", "done", jQuery.Callbacks( "once memory" ),
                    jQuery.Callbacks( "once memory" ), 0, "resolved" ],
                [ "reject", "fail", jQuery.Callbacks( "once memory" ),
                    jQuery.Callbacks( "once memory" ), 1, "rejected" ]
            ],
            state = "pending",
            promise = {
                state: function() {
                    return state;
                },
                // 同时添加done和fail句柄
                always: function() {
                    deferred.done( arguments ).fail( arguments );
                    return this;
                },
                "catch": function( fn ) {
                    return promise.then( null, fn );
                },
                then: function( onFulfilled, onRejected, onProgress ) {
                    var maxDepth = 0;
                    function resolve( depth, deferred, handler, special ) {
                        return function() {
                            var that = this,
                                args = arguments,
                                mightThrow = function() {
                                    var returned, then;

                                    // Support: Promises/A+ section 2.3.3.3.3
                                    // https://promisesaplus.com/#point-59
                                    // Ignore double-resolution attempts
                                    if ( depth < maxDepth ) {
                                        return;
                                    }

                                    returned = handler.apply( that, args );

                                    // Support: Promises/A+ section 2.3.1
                                    // https://promisesaplus.com/#point-48
                                    if ( returned === deferred.promise() ) {
                                        throw new TypeError( "Thenable self-resolution" );
                                    }

                                    // Support: Promises/A+ sections 2.3.3.1, 3.5
                                    // https://promisesaplus.com/#point-54
                                    // https://promisesaplus.com/#point-75
                                    // Retrieve `then` only once
                                    then = returned &&

                                        // Support: Promises/A+ section 2.3.4
                                        // https://promisesaplus.com/#point-64
                                        // Only check objects and functions for thenability
                                        ( typeof returned === "object" ||
                                            typeof returned === "function" ) &&
                                        returned.then;

                                    // Handle a returned thenable
                                    if ( jQuery.isFunction( then ) ) {

                                        // Special processors (notify) just wait for resolution
                                        if ( special ) {
                                            then.call(
                                                returned,
                                                resolve( maxDepth, deferred, Identity, special ),
                                                resolve( maxDepth, deferred, Thrower, special )
                                            );

                                        // Normal processors (resolve) also hook into progress
                                        } else {

                                            // ...and disregard older resolution values
                                            maxDepth++;

                                            then.call(
                                                returned,
                                                resolve( maxDepth, deferred, Identity, special ),
                                                resolve( maxDepth, deferred, Thrower, special ),
                                                resolve( maxDepth, deferred, Identity,
                                                    deferred.notifyWith )
                                            );
                                        }

                                    // Handle all other returned values
                                    } else {

                                        // Only substitute handlers pass on context
                                        // and multiple values (non-spec behavior)
                                        if ( handler !== Identity ) {
                                            that = undefined;
                                            args = [ returned ];
                                        }

                                        // Process the value(s)
                                        // Default process is resolve
                                        ( special || deferred.resolveWith )( that, args );
                                    }
                                },

                                // Only normal processors (resolve) catch and reject exceptions
                                // 只有普通的process能处理异常,其余的要进行捕获,这里不是特别明白,应该是因为没有改最终的状态吧
                                process = special ?
                                    mightThrow :
                                    function() {
                                        try {
                                            mightThrow();
                                        } catch ( e ) {

                                            if ( jQuery.Deferred.exceptionHook ) {
                                                jQuery.Deferred.exceptionHook( e,
                                                    process.stackTrace );
                                            }

                                            // Support: Promises/A+ section 2.3.3.3.4.1
                                            // https://promisesaplus.com/#point-61
                                            // Ignore post-resolution exceptions
                                            if ( depth + 1 >= maxDepth ) {

                                                // Only substitute handlers pass on context
                                                // and multiple values (non-spec behavior)
                                                if ( handler !== Thrower ) {
                                                    that = undefined;
                                                    args = [ e ];
                                                }

                                                deferred.rejectWith( that, args );
                                            }
                                        }
                                    };

                            // Support: Promises/A+ section 2.3.3.3.1
                            // https://promisesaplus.com/#point-57
                            // Re-resolve promises immediately to dodge false rejection from
                            // subsequent errors
                            if ( depth ) {
                                process();
                            } else {

                                // Call an optional hook to record the stack, in case of exception
                                // since it&#39;s otherwise lost when execution goes async
                                if ( jQuery.Deferred.getStackHook ) {
                                    process.stackTrace = jQuery.Deferred.getStackHook();
                                }
                                window.setTimeout( process );
                            }
                        };
                    }

                    return jQuery.Deferred( function( newDefer ) {

                        // progress_handlers.add( ... )
                        tuples[ 0 ][ 3 ].add(
                            resolve(
                                0,
                                newDefer,
                                jQuery.isFunction( onProgress ) ?
                                    onProgress :
                                    Identity,
                                newDefer.notifyWith
                            )
                        );

                        // fulfilled_handlers.add( ... )
                        tuples[ 1 ][ 3 ].add(
                            resolve(
                                0,
                                newDefer,
                                jQuery.isFunction( onFulfilled ) ?
                                    onFulfilled :
                                    Identity
                            )
                        );

                        // rejected_handlers.add( ... )
                        tuples[ 2 ][ 3 ].add(
                            resolve(
                                0,
                                newDefer,
                                jQuery.isFunction( onRejected ) ?
                                    onRejected :
                                    Thrower
                            )
                        );
                    } ).promise();
                },

                // Get a promise for this deferred
                // If obj is provided, the promise aspect is added to the object
                // 通过该promise对象返回一个新的扩展promise对象或自身
                promise: function( obj ) {
                    return obj != null ? jQuery.extend( obj, promise ) : promise;
                }
            },
            deferred = {};

        // Add list-specific methods
        // 给promise添加done/fail/progress事件,并添加互相的影响关系,并为deferred对象添加3个事件函数notify/resolve/reject
        jQuery.each( tuples, function( i, tuple ) {
            var list = tuple[ 2 ],
                stateString = tuple[ 5 ];

            // promise.progress = list.add
            // promise.done = list.add
            // promise.fail = list.add
            promise[ tuple[ 1 ] ] = list.add;

            // Handle state
            // 只有done和fail有resolved和rejected状态字段,给两个事件添加回调,禁止再次done或者fail,锁住progress不允许执行回调
            if ( stateString ) {
                list.add(
                    function() {

                        // state = "resolved" (i.e., fulfilled)
                        // state = "rejected"
                        state = stateString;
                    },

                    // rejected_callbacks.disable
                    // fulfilled_callbacks.disable
                    tuples[ 3 - i ][ 2 ].disable,

                    // progress_callbacks.lock
                    tuples[ 0 ][ 2 ].lock
                );
            }

            // progress_handlers.fire
            // fulfilled_handlers.fire
            // rejected_handlers.fire
            // 执行第二个回调列表
            list.add( tuple[ 3 ].fire );

            // deferred.notify = function() { deferred.notifyWith(...) }
            // deferred.resolve = function() { deferred.resolveWith(...) }
            // deferred.reject = function() { deferred.rejectWith(...) }
            // 绑定notify/resolve/reject的事件,实际执行的函数体为加入上下文的With函数
            deferred[ tuple[ 0 ] ] = function() {
                deferred[ tuple[ 0 ] + "With" ]( this === deferred ? undefined : this, arguments );
                return this;
            };

            // deferred.notifyWith = list.fireWith
            // deferred.resolveWith = list.fireWith
            // deferred.rejectWith = list.fireWith
            deferred[ tuple[ 0 ] + "With" ] = list.fireWith;
        } );

        // Make the deferred a promise
        // 将deferred扩展为一个promise对象
        promise.promise( deferred );

        // Call given func if any
        // 在创建前执行传入的回调函数进行修改
        if ( func ) {
            func.call( deferred, deferred );
        }

        // All done!
        return deferred;
    },
登入後複製

jQuery.when方法

$.when()提供一种方法执行一个或多个函数的回调函数。如果传入一个延迟对象,则返回该对象的Promise对象,可以继续绑定其余回调,在执行结束状态之后也同时调用其when回调函数。如果传入多个延迟对象,则返回一个新的master延迟对象,跟踪所有的聚集状态,如果都成功解析完成,才调用其when回调函数;如果有一个失败,则全部失败,执行错误回调。

其使用方法:

$.when($.ajax("/page1.php"), $.ajax("/page2.php"))
  .then(myFunc, myFailure);
登入後複製

其所有源码实现和注释为(能力有限,有些地方实在不能准确理解执行流程):

// 给when传递的对象绑定master.resolve和master.reject,用于聚集多异步对象的状态
function adoptValue( value, resolve, reject, noValue ) {
    var method;
    try {
        // Check for promise aspect first to privilege synchronous behavior
        // 如果when传入的参数promise方法可用,则封装promise并添加done和fail方法调用resolve和reject
        if ( value && jQuery.isFunction( ( method = value.promise ) ) ) {
            method.call( value ).done( resolve ).fail( reject );

        // Other thenables
        // 否则,就判断传入参数的then方法是否可用,如果可用就传入resolve和reject方法
        } else if ( value && jQuery.isFunction( ( method = value.then ) ) ) {
            method.call( value, resolve, reject );

        // Other non-thenables
        // 如果均不可用,则为非异步对象,直接resolve解析原值
        } else {

            // Control `resolve` arguments by letting Array#slice cast boolean `noValue` to integer:
            // * false: [ value ].slice( 0 ) => resolve( value )
            // * true: [ value ].slice( 1 ) => resolve()
            resolve.apply( undefined, [ value ].slice( noValue ) );
        }

    // For Promises/A+, convert exceptions into rejections
    // Since jQuery.when doesn&#39;t unwrap thenables, we can skip the extra checks appearing in
    // Deferred#then to conditionally suppress rejection.
    } catch ( value ) {

        // Support: Android 4.0 only
        // Strict mode functions invoked without .call/.apply get global-object context
        // 一个安卓4.0的bug,这里不做阐释
        reject.apply( undefined, [ value ] );
    }
}

// Deferred helper
    when: function( singleValue ) {
        var
            // count of uncompleted subordinates
            remaining = arguments.length,

            // count of unprocessed arguments
            i = remaining,

            // subordinate fulfillment data
            resolveContexts = Array( i ),
            resolveValues = slice.call( arguments ),

            // the master Deferred
            master = jQuery.Deferred(),

            // subordinate callback factory
            // 将每一个响应的环境和值都保存到列表里,在全部完成后统一传给主Promise用于执行
            updateFunc = function( i ) {
                return function( value ) {
                    resolveContexts[ i ] = this;
                    resolveValues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value;
                    if ( !( --remaining ) ) {
                        master.resolveWith( resolveContexts, resolveValues );
                    }
                };
            };

        // Single- and empty arguments are adopted like Promise.resolve
        // 如果只有一个参数,则直接将其作为master的回调
        if ( remaining <= 1 ) {
            adoptValue( singleValue, master.done( updateFunc( i ) ).resolve, master.reject,
                !remaining );

            // Use .then() to unwrap secondary thenables (cf. gh-3000)
            if ( master.state() === "pending" ||
                jQuery.isFunction( resolveValues[ i ] && resolveValues[ i ].then ) ) {

                return master.then();
            }
        }

        // Multiple arguments are aggregated like Promise.all array elements
        // 多参数时,进行所有参数的解析状态聚合到master上
        while ( i-- ) {
            adoptValue( resolveValues[ i ], updateFunc( i ), master.reject );
        }

        return master.promise();
    }
登入後複製

后续

本来想把jQuery.DeferredjQuery.ajax以及ES6Promise对象给统一讲一下,结果发现牵涉的东西太多,每一个都可以单独写一篇文章,怕大家说太长不看,这里先写第一部分jQuery.Deferred吧,后续再补充另外两篇。

jQuery的文档很容易,使用也很方便,但其实真正想要讲好很复杂,更不要说写篇源码分析文章了。真的是努力理解设计者的思路,争取每行都能理解边界条件,但踩坑太少,应用场景太少,确实有很大的疏漏,希望大家能够理解,不要偏听一面之词。


以上是jQuery原始碼解析Deferred非同步物件的方法的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

<🎜>:泡泡膠模擬器無窮大 - 如何獲取和使用皇家鑰匙
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
北端:融合系統,解釋
3 週前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

熱門話題

Java教學
1664
14
CakePHP 教程
1423
52
Laravel 教程
1319
25
PHP教程
1269
29
C# 教程
1248
24
jQuery中如何使用PUT請求方式? jQuery中如何使用PUT請求方式? Feb 28, 2024 pm 03:12 PM

jQuery中如何使用PUT請求方式?在jQuery中,發送PUT請求的方法與發送其他類型的請求類似,但需要注意一些細節和參數設定。 PUT請求通常用於更新資源,例如更新資料庫中的資料或更新伺服器上的檔案。以下是在jQuery中使用PUT請求方式的具體程式碼範例。首先,確保引入了jQuery庫文件,然後可以透過以下方式發送PUT請求:$.ajax({u

jQuery小技巧:快速修改頁面所有a標籤的文本 jQuery小技巧:快速修改頁面所有a標籤的文本 Feb 28, 2024 pm 09:06 PM

標題:jQuery小技巧:快速修改頁面所有a標籤的文字在網頁開發中,我們經常需要對頁面中的元素進行修改和操作。使用jQuery時,有時候需要一次修改頁面中所有a標籤的文字內容,這樣可以節省時間和精力。以下將介紹如何使用jQuery快速修改頁面所有a標籤的文本,同時給出具體的程式碼範例。首先,我們需要引入jQuery庫文件,確保在頁面中引入了以下程式碼:&lt

使用jQuery修改所有a標籤的文字內容 使用jQuery修改所有a標籤的文字內容 Feb 28, 2024 pm 05:42 PM

標題:使用jQuery修改所有a標籤的文字內容jQuery是一款受歡迎的JavaScript庫,被廣泛用於處理DOM操作。在網頁開發中,經常會遇到需要修改頁面上連結標籤(a標籤)的文字內容的需求。本文將介紹如何使用jQuery來實現這個目標,並提供具體的程式碼範例。首先,我們需要在頁面中引入jQuery庫。在HTML檔案中加入以下程式碼:

jQuery如何移除元素的height屬性? jQuery如何移除元素的height屬性? Feb 28, 2024 am 08:39 AM

jQuery如何移除元素的height屬性?在前端開發中,經常會遇到需要操作元素的高度屬性的需求。有時候,我們可能需要動態改變元素的高度,而有時候又需要移除元素的高度屬性。本文將介紹如何使用jQuery來移除元素的高度屬性,並提供具體的程式碼範例。在使用jQuery操作高度屬性之前,我們首先需要了解CSS中的height屬性。 height屬性用於設定元素的高度

Python asyncio 進階指南:從初學者到專家 Python asyncio 進階指南:從初學者到專家 Mar 04, 2024 am 09:43 AM

並發和非同步編程並發編程處理同時執行的多個任務,非同步編程是一種並發編程,其中任務不會阻塞線程。 asyncio是python中用於非同步程式設計的函式庫,它允許程式在不阻塞主執行緒的情況下執行I/O操作。事件循環asyncio的核心是事件循環,它監控I/O事件並調度相應的任務。當一個協程準備好時,事件循環會執行它,直到它等待I/O操作。然後,它會暫停協程並繼續執行其他協程。協程協程是可暫停和恢復執行的函數。 asyncdef關鍵字用於建立協程。協程使用await關鍵字等待I/O作業完成。 asyncio的基礎以下

了解jQuery中eq的作用及應用場景 了解jQuery中eq的作用及應用場景 Feb 28, 2024 pm 01:15 PM

jQuery是一種流行的JavaScript庫,被廣泛用於處理網頁中的DOM操作和事件處理。在jQuery中,eq()方法是用來選擇指定索引位置的元素的方法,具體使用方法和應用場景如下。在jQuery中,eq()方法選擇指定索引位置的元素。索引位置從0開始計數,即第一個元素的索引是0,第二個元素的索引是1,依此類推。 eq()方法的語法如下:$("s

Java異常處理中的非同步與非阻塞技術 Java異常處理中的非同步與非阻塞技術 May 01, 2024 pm 05:42 PM

非同步和非阻塞技術可用於補充傳統異常處理,允許創建更具響應性和高效的Java應用程式:非同步異常處理:在另一個執行緒或進程中處理異常,讓主執行緒繼續執行,避免阻塞。非阻塞異常處理:涉及I/O操作出錯時事件驅動的異常處理,避免阻塞線程,由事件循環處理異常。

使用jQuery為表格新增一行的方法介紹 使用jQuery為表格新增一行的方法介紹 Feb 29, 2024 am 08:12 AM

jQuery是一個受歡迎的JavaScript函式庫,廣泛用於網頁開發。在網頁開發過程中,經常需要透過JavaScript動態地在表格中新增一行。本文將介紹如何使用jQuery為表格新增一行,並提供具體的程式碼範例。首先,我們需要在HTML頁面中引入jQuery函式庫。可以透過以下程式碼在標籤中引入jQuery庫:

See all articles