面試題:promise的鏈式怎麼實現的

山頭人漢波發表於2022-04-18

前言

之前有過一次面試,面試官問 promise 相關的知識點,然後我回答了,他追問說 promise 的鏈式怎麼實現?我當時沒反應過來。面試官很有耐心,說 jquery 也是有鏈式的,你看過 jquery 的原始碼嗎?它的鏈式怎麼寫的?我還是不知道,後來沒通過面試,這個知識點常被我回憶,現在正好有時間,來寫一寫

正文

答案是:返回this

先來一個例子:

var person = {
    name: 'johan',
    age: 28,
    sayName: function() {
        console.log('my name is' + this.name)
    },
    sayAge: function() {
        console.log('my age is ' + this.age)
    }
}

命名一個物件,它有兩個方法,sayName 和 sayAge ,如果我想這樣表示 person.sayName().sayAge() 呢?怎麼做,在方法 sayName 和 sayAge 中返回 this,即

var person = {
    name: 'johan',
    age: 28,
    sayName: function() {
        console.log('my name is' + this.name)
        return this;
    },
    sayAge: function() {
        console.log('my age is ' + this.age)
        return this;
    }
}

這就是表示,呼叫方法 sayName 、sayAge 後,返回撥用者,即例子 person.sayName() ,person 呼叫 sayName,呼叫完後返回值還是 person。所以它可以繼續鏈式呼叫 sayAge,因為它表示的還是 person

Promise 中的鏈式

Promise 本身沒有鏈式,但是 Promise 的例項物件中的 then 有鏈式

function MyPromise(executor) {
    
}

MyPromise.prototype.then = function (onFulfilled, onRejected) {
    return new Promise((resolve, reject) => {
        ...
    })
}

當你使用 Promise 時,一般是這樣使用:

let promise = new Promise((resolve, reject) => {
    setTimeout(resolve, 1000)
})
promise.then(() => {
    console.log('1s後顯示')
})

如果加上鍊式

promise.then(() => {
    console.log('1s後顯示,第一個')
}).then(() => {
    console.log('1s後顯示,第二個')
})

所以很明顯,每呼叫一次 then,就是返回一個例項物件(return new Promise

Jquery 中的鏈式

原始碼太多內容,就拿 core.js 中的程式碼為例子

jQuery.fn = jQuery.prototype = {

    // The current version of jQuery being used
    jquery: version,

    constructor: jQuery,

    // The default length of a jQuery object is 0
    length: 0,

    toArray: function() {
        return slice.call( this );
    },

    // Get the Nth element in the matched element set OR
    // Get the whole matched element set as a clean array
    get: function( num ) {

        // Return all the elements in a clean array
        if ( num == null ) {
            return slice.call( this );
        }

        // Return just the one element from the set
        return num < 0 ? this[ num + this.length ] : this[ num ];
    },

    // Take an array of elements and push it onto the stack
    // (returning the new matched element set)
    pushStack: function( elems ) {

        // Build a new jQuery matched element set
        var ret = jQuery.merge( this.constructor(), elems );

        // Add the old object onto the stack (as a reference)
        ret.prevObject = this;

        // Return the newly-formed element set
        return ret;
    },

    // Execute a callback for every element in the matched set.
    each: function( callback ) {
        return jQuery.each( this, callback );
    },

    map: function( callback ) {
        return this.pushStack( jQuery.map( this, function( elem, i ) {
            return callback.call( elem, i, elem );
        } ) );
    },

    slice: function() {
        return this.pushStack( slice.apply( this, arguments ) );
    },

    first: function() {
        return this.eq( 0 );
    },

    last: function() {
        return this.eq( -1 );
    },

    even: function() {
        return this.pushStack( jQuery.grep( this, function( _elem, i ) {
            return ( i + 1 ) % 2;
        } ) );
    },

    odd: function() {
        return this.pushStack( jQuery.grep( this, function( _elem, i ) {
            return i % 2;
        } ) );
    },

    eq: function( i ) {
        var len = this.length,
            j = +i + ( i < 0 ? len : 0 );
        return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] );
    },

    end: function() {
        return this.prevObject || this.constructor();
    }
};

我們不用看全部,但看其中的方法,是不是和最開始的例子很像——return this

所以鏈式不可怕,可怕的是,動都不動就自我勸退

本文參與了 SegmentFault 思否徵文「如何“反殺”面試官?」,歡迎正在閱讀的你也加入。

相關文章