最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

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

概念

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

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

使用享元模式

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

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

優(yōu)化文件上傳

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

常規(guī)方式

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

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
}

接下來,我們將初始化上傳組件,代碼如下:

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對象。而實際上的Upload對象會非常大。使用這種方式我們有多少個文件就需要創(chuàng)建多少個Upload對象,接下來我們將使用享元模式優(yōu)化代碼。

享元模式重構(gòu)

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

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

根據(jù)上面的分析,我們首先把外部狀態(tà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)該如何使用呢?之前我們可以通過init方法創(chuàng)建一個上傳組件,接下來,我們需要創(chuàng)建兩個對象:UploadFactory用來創(chuàng)建Upload對象,uploadManager用來管理上傳對象(包括添加上傳組件和為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中有一個create方法來創(chuàng)建Upload對象并存到createdFlyWeightObjs中,而對于相同的uploadType我們也只會創(chuàng)建一個Upload

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

因此,當(dāng)我們需要去上傳文件時,我們需要這樣修改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);
  }
};

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

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

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

總結(jié)

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

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

享元模式的適用性

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

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

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

相關(guān)文章

最新評論

贺兰县| 崇州市| 江陵县| 平泉县| 同江市| 绥棱县| 富宁县| 稷山县| 茂名市| 古丈县| 石城县| 开封县| 枣庄市| 留坝县| 綦江县| 监利县| 宁安市| 桐柏县| 新泰市| 高阳县| 麻栗坡县| 阿克苏市| 如皋市| 巴里| 上林县| 南木林县| 蕉岭县| 吴桥县| 竹山县| 罗平县| 交城县| 保靖县| 旬阳县| 林口县| 砀山县| 拉孜县| 海兴县| 杨浦区| 神木县| 岚皋县| 印江|