[js]一道緩存類(lèi)面試題

在開(kāi)發(fā)過(guò)程中踩了一個(gè)坑,覺(jué)得挺有意思,就順手編成了一道題。

// Cache是一個(gè)緩存類(lèi),使用時(shí)先在new方法中注冊(cè)獲取數(shù)據(jù)的方法,然后可通過(guò)get方法獲取數(shù)據(jù),
// 并且只有第一次調(diào)用get會(huì)真正調(diào)用new中注冊(cè)的方法獲取數(shù)據(jù),以后都直接從緩存中返回。

function Cache () {
    this.store = {}
}

Cache.prototype.add = function (name, fn) {
    if (!name || !fn || typeof fn !== 'function') {
        return
    }
    this.store[name] = {name, fn, data: {}}
}

Cache.prototype.get = function (name, key) {
    const self = this.store[name]
    key = key || 1
    if (self.data[key]) {
        return Promise.resolve(self.data[key])
    }
    return self.fn(key).then(data => {
        self.data[key] = data
        return data
    })
}

Cache.prototype.clear = function (name, key) {
    this.store[name].data[key] = null
}

Cache.prototype.clearAll = function (name) {
    this.store[name].data = {}
}

// 1.下面的代碼說(shuō)明Cache的實(shí)現(xiàn)存在一個(gè)bug,嘗試修復(fù)它

const c = new Cache()

c.add('foo', function (key) {
    return Promise.resolve([1])
})

c.get('foo').then(
    list0 => {
        console.log(list0)
        list0.push(2)
        return c.get('foo')
    }).then(
    list1 => {
        console.log(list1)
        list1.push(3)
        return c.get('foo')
    }).then(
    list2 => {
        console.log(list2)
    })

// 2.對(duì)以上代碼提出一些改進(jìn)意見(jiàn)
// 3.當(dāng)同時(shí)對(duì)同一個(gè)name,同一個(gè)key發(fā)起多個(gè)get,且緩存不存在時(shí),會(huì)導(dǎo)致fn多次執(zhí)行,優(yōu)化這個(gè)問(wèn)題

以下是解答:

  • 作為一個(gè)緩存類(lèi),每次讀取到的數(shù)據(jù)應(yīng)該是相同的,顯然這里并不是。那么是哪里出了問(wèn)題?在js中如果返回值不是基礎(chǔ)類(lèi)型(如Number,String)返回的會(huì)是一個(gè)對(duì)象引用,而這里正是返回了緩存對(duì)象的引用,才導(dǎo)致調(diào)用者可以隨意更改緩存的內(nèi)容。怎么解決呢?拷貝后再返回,切斷緩存與返回值間的關(guān)聯(lián),而且必須是深拷貝才能徹底切斷。考慮使用場(chǎng)景是獲取后端數(shù)據(jù),這個(gè)地方的用json序列化實(shí)現(xiàn)。

  • get方法的參數(shù)key有默認(rèn)值1,這個(gè)邏輯并不正確。如果key為空會(huì)導(dǎo)致調(diào)用new中注冊(cè)的數(shù)據(jù)獲取方法時(shí)錯(cuò)誤地傳入key的默認(rèn)值1。

Cache.prototype.get = function (name, key) {
  const self = this.store[name]
  if (self.data[key]) {
    return Promise.resolve(JSON.parse(self.data[key]))
  }
  return self.fn(key).then(data => {
    self.data[key] = JSON.stringify(data)
    return data
  })
}

我在剛編出這道的時(shí)候覺(jué)得不過(guò)就是一個(gè)考察return返回引用的題目,并不多難,但是在問(wèn)過(guò)幾個(gè)人以后才發(fā)現(xiàn)沒(méi)那么簡(jiǎn)單。首先需要對(duì)使用原型鏈構(gòu)造類(lèi)有基本的了解,對(duì)于那些如果是僅僅只是實(shí)現(xiàn)一下業(yè)務(wù)邏輯,不做任何抽象和封裝的ctrl+v工程師而言恐怕確實(shí)不需要懂。其次是Promise和ES6語(yǔ)法,相對(duì)來(lái)說(shuō)這些也是比較新的東西。

為什么人與人之間差別就那么大呢?同一個(gè)技術(shù)點(diǎn)對(duì)有的人來(lái)說(shuō)是不必多說(shuō)的基礎(chǔ),對(duì)于另一些人來(lái)說(shuō)卻是天方夜譚…

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語(yǔ)法,類(lèi)相關(guān)的語(yǔ)法,內(nèi)部類(lèi)的語(yǔ)法,繼承相關(guān)的語(yǔ)法,異常的語(yǔ)法,線(xiàn)程的語(yǔ)...
    子非魚(yú)_t_閱讀 34,719評(píng)論 18 399
  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,569評(píng)論 19 139
  • *面試心聲:其實(shí)這些題本人都沒(méi)怎么背,但是在上海 兩周半 面了大約10家 收到差不多3個(gè)offer,總結(jié)起來(lái)就是把...
    Dove_iOS閱讀 27,624評(píng)論 30 472
  • 03344——陳敏芳 當(dāng)我們問(wèn)自己“愛(ài)會(huì)給誰(shuí)?”時(shí),從心底跳出的,大多是我們的親人、朋友、鄰居、同學(xué)……是那...
    陳敏Amy閱讀 212評(píng)論 0 0
  • 大部分的家庭,都算和睦,曬親情的也不少,即便父母不和睦,能各自過(guò)好自己的生活也不少,可偏偏有些卻不是這樣。生活中這...
    不加雞精味精閱讀 425評(píng)論 4 2

友情鏈接更多精彩內(nèi)容