亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

詳解JavaScript設(shè)計(jì)模式中的享元模式

 更新時(shí)間:2023年06月09日 08:28:06   作者:liangyue  
享元模式是一種用于性能優(yōu)化的模式。享元模式的核心是運(yùn)用共享技術(shù)來(lái)有效支持大量細(xì)粒度的對(duì)象.如果系統(tǒng)中創(chuàng)建了大量類似的對(duì)象而導(dǎo)致內(nèi)存占用過(guò)高,本文通過(guò)介紹書(shū)中文件上傳的優(yōu)化案例來(lái)說(shuō)明享元模式的使用方式和作用,需要的朋友可以參考下

概念

在《JavaScript設(shè)計(jì)模式與開(kāi)發(fā)實(shí)踐》 中是這樣描述享元模式的:是一種用于性能優(yōu)化的模式。享元模式的核心是運(yùn)用共享技術(shù)來(lái)有效支持大量細(xì)粒度的對(duì)象

如果系統(tǒng)中創(chuàng)建了大量類似的對(duì)象而導(dǎo)致內(nèi)存占用過(guò)高,享元模式就非常有用了。享元模式的目標(biāo)是盡量減少共享對(duì)象的數(shù)量

使用享元模式

享元模式要求將對(duì)象的屬性劃分為內(nèi)部狀態(tài)外部狀態(tài)。關(guān)于如何劃分內(nèi)部狀態(tài)和外部狀態(tài),下面有幾條經(jīng)驗(yàn):

  • 內(nèi)部狀態(tài)存儲(chǔ)于對(duì)象內(nèi)部
  • 內(nèi)部狀態(tài)可以被一些對(duì)象共享
  • 內(nèi)部狀態(tài)獨(dú)立于具體的場(chǎng)景,通常不會(huì)改變
  • 外部狀態(tài)取決于具體的場(chǎng)景,并根據(jù)場(chǎng)景而變化,外部狀態(tài)不能被共享

優(yōu)化文件上傳

我們通過(guò)介紹書(shū)中文件上傳的優(yōu)化案例來(lái)說(shuō)明享元模式的使用方式和作用。在這個(gè)例子中,作者通過(guò)享元模式提升了程序的性能,接下來(lái)我們來(lái)講述這個(gè)例子。

常規(guī)方式

在上傳功能的開(kāi)發(fā)中,遇到了一個(gè)對(duì)象爆炸的問(wèn)題。上傳功能既支持依照隊(duì)列一個(gè)一個(gè)上傳,也可以支持選擇2000個(gè)文件同時(shí)上傳。在第一版開(kāi)發(fā)中,程序中將同時(shí)new了2000個(gè)upload對(duì)象,結(jié)果就是在IE瀏覽器下直接進(jìn)入假死狀態(tài)。這里,我們先寫(xiě)一下簡(jiǎn)化后的偽代碼:

var id = 0;
var Upload = function(uploadType, fileName, fileSize) {
  this.uploadType = uploadType;
  this.fileName = fileName;
  this.fileSize = fileSize;
  this.dom = null;
}
Upload.prototype.init = function(id) {
  const that = this;
  this.id = id;
  this.dom = document.createElement('div');
  this.dom.innerHTML = '<span>文件名稱:' + fileName + ', 文件大小: ' + fileSize + '</span>' +
    '<button class="delFile">刪除</button>';
  dom.querySelector('.delFile').onclick = function () {
    that.delFile();
  }
}
Upload.prototype.delFile = funtion() {
  // delFile
}

接下來(lái),我們將初始化上傳組件,代碼如下:

window.startUpload = function(uploadType, files) {
  for (var i = 0, file; file = files[i++];) {
    var uploadObj = new Upload(uploadType, file.fileName, file.fileSize);
    uploadObj.init(id++)
  }
}

在上面的代碼中,uploadType可以支持不同類型的上傳模式,例如:瀏覽器插件、Flash和表單上傳等。當(dāng)用戶選擇好文件后,調(diào)用window下的startUpload函數(shù),在函數(shù)中將創(chuàng)建Upload對(duì)象。而實(shí)際上的Upload對(duì)象會(huì)非常大。使用這種方式我們有多少個(gè)文件就需要?jiǎng)?chuàng)建多少個(gè)Upload對(duì)象,接下來(lái)我們將使用享元模式優(yōu)化代碼。

享元模式重構(gòu)

首先,我們需要先確定Upload對(duì)象的屬性的內(nèi)部狀態(tài)外部狀態(tài)。

Upload對(duì)象必須依賴uploadType屬性才可以工作,只有在創(chuàng)建的時(shí)候明確了組件的類型,才可以調(diào)用各自的方法,而fileNamefileSize 是根據(jù)場(chǎng)景而變化的,不能被共享。因此,我們可以確定:uploadType屬性為內(nèi)部狀態(tài),而fileNamefileSize為外部狀態(tài)。

根據(jù)上面的分析,我們首先把外部狀態(tài)剝離出來(lái),Upload函數(shù)中只保留uploadType參數(shù):

var Upload = function (uploadType) {
  this.uploadType = uploadType;
}
Upload.prototype.delFile = function (id) {
  uploadManager.setExternalState(id, this);
  return this.dom.parentNode.removeChild(this.dom);
}

我們應(yīng)該如何使用呢?之前我們可以通過(guò)init方法創(chuàng)建一個(gè)上傳組件,接下來(lái),我們需要?jiǎng)?chuàng)建兩個(gè)對(duì)象:UploadFactory用來(lái)創(chuàng)建Upload對(duì)象,uploadManager用來(lái)管理上傳對(duì)象(包括添加上傳組件和為Upload設(shè)置正確的處理文件),代碼如下:

var UploadFactory = (function () {
  var createdFlyWeightObjs = {};
  return {
    create: function (uploadType) {
      if (createdFlyWeightObjs[uploadType]) {
        return createdFlyWeightObjs[uploadType];
      }
      return createdFlyWeightObjs[uploadType] = new Upload(uploadType);
    }
  }
})()
var uploadManager = (function () {
  var uploadDatabase = {};
  return {
    add: function (id, uploadType, fileName, fileSize) {
      var flyWeightObj = UploadFactory.create(uploadType);
      var dom = document.createElement('div');
      dom.innerHTML =
        '<span>文件名稱:' + fileName + ', 文件大小: ' + fileSize + '</span>' +
        '<button class="delFile">刪除</button>';
      dom.querySelector('.delFile').onclick = function () {
        flyWeightObj.delFile(id);
      }
      // 添加上傳組件
      uploadDatabase[id] = {
        fileName: fileName,
        fileSize: fileSize,
        dom: dom
      };
      return flyWeightObj;
    },
    setExternalState: function (id, flyWeightObj) {
      var uploadData = uploadDatabase[id];
      for (var i in uploadData) {
        flyWeightObj[i] = uploadData[i];
      }
    }
  }
})()

代碼分析

UploadFactory: 根據(jù)代碼不難理解,UploadFactory中有一個(gè)create方法來(lái)創(chuàng)建Upload對(duì)象并存到createdFlyWeightObjs中,而對(duì)于相同的uploadType我們也只會(huì)創(chuàng)建一個(gè)Upload

uploadManager: 這個(gè)對(duì)象將不同文件的fileName、fileSize等屬性保存到uploadDatabase中,當(dāng)執(zhí)行setExternalStates時(shí)會(huì)將正確的文件對(duì)象設(shè)置到flyWeightObj,在執(zhí)行add時(shí),我們會(huì)創(chuàng)建Upload對(duì)象,并將上傳文件保存到uploadDatabase

因此,當(dāng)我們需要去上傳文件時(shí),我們需要這樣修改window.startUpload,代碼如下:

var id = 0;
window.startUpload = function (uploadType, files) {
  for (var i = 0, file; file = files[i++];) {
    var uploadObj = uploadManager.add(++id, uploadType, file.fileName, file.fileSize);
  }
};

通過(guò)ploadManager.add創(chuàng)建時(shí),我們并不會(huì)有幾個(gè)文件就創(chuàng)建幾個(gè)Upload對(duì)象,相同的uploadType會(huì)共享一個(gè)Upload。當(dāng)我們執(zhí)行某一個(gè)文件的刪除時(shí):

我們會(huì)先通過(guò)uploadManager.setExternalState方法設(shè)置需要操作的文件,包括fileName、fileSize、dom,然后執(zhí)行相關(guān)的刪除邏輯,如:代碼中的是將當(dāng)前的dom刪除,即可以直接使用this.dom。

使用享元模式重構(gòu)后,就可以大量的減少創(chuàng)建Upload對(duì)象,從而實(shí)現(xiàn)性能優(yōu)化。

總結(jié)

享元模式是為了解決性能問(wèn)題而生的模式,在上述的例子中,我們通過(guò)享元模式減少了對(duì)象的創(chuàng)建從而提升了瀏覽器的性能,但在很多開(kāi)源的代碼中我還沒(méi)有找到使用享元模式的真實(shí)案例。

但享元模式的思想倒是隨處可見(jiàn),例如vue、react等在處理dom元素更新時(shí)都會(huì)通過(guò)diff算法來(lái)實(shí)現(xiàn)dom節(jié)點(diǎn)的復(fù)用,從而提升一定的性能。

享元模式的適用性

最后,列出書(shū)中總結(jié)的該模式的適用性,當(dāng)以下情況發(fā)生時(shí),便可以考慮使用享元模式:

  • 一個(gè)程序使用了大量的相似對(duì)象
  • 由于使用了大量對(duì)象,造成很大的內(nèi)存開(kāi)銷
  • 對(duì)象的大多數(shù)狀態(tài)都可以變?yōu)?strong>外部狀態(tài)
  • 剝離出對(duì)象的外部狀態(tài)后,可以使用相對(duì)較少的共享對(duì)象取代大量對(duì)象

以上就是詳解JavaScript設(shè)計(jì)模式中的享元模式的詳細(xì)內(nèi)容,更多關(guān)于JavaScript 享元模式的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評(píng)論