欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

詳解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)存占用過高,享元模式就非常有用了。享元模式的目標是盡量減少共享對象的數(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和表單上傳等。當用戶選擇好文件后,調(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中,當執(zhí)行setExternalStates時會將正確的文件對象設(shè)置到flyWeightObj,在執(zhí)行add時,我們會創(chuàng)建Upload對象,并將上傳文件保存到uploadDatabase

因此,當我們需要去上傳文件時,我們需要這樣修改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。當我們執(zhí)行某一個文件的刪除時:

我們會先通過uploadManager.setExternalState方法設(shè)置需要操作的文件,包括fileName、fileSize、dom,然后執(zhí)行相關(guān)的刪除邏輯,如:代碼中的是將當前的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é)的該模式的適用性,當以下情況發(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)文章

  • 小程序接口的promise化的實現(xiàn)方法

    小程序接口的promise化的實現(xiàn)方法

    這篇文章主要介紹了小程序接口的promise化的實現(xiàn)方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-12-12
  • localStorage實現(xiàn)便簽小程序

    localStorage實現(xiàn)便簽小程序

    這篇文章主要為大家詳細介紹了localStorage實現(xiàn)便簽小程序的相關(guān)資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-11-11
  • JavaScript實現(xiàn)廣告彈窗效果

    JavaScript實現(xiàn)廣告彈窗效果

    這篇文章主要為大家詳細介紹了JavaScript實現(xiàn)廣告彈窗效果,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-08-08
  • 微信小程序?qū)崿F(xiàn)瀑布流分頁滾動加載

    微信小程序?qū)崿F(xiàn)瀑布流分頁滾動加載

    這篇文章主要為大家詳細介紹了微信小程序?qū)崿F(xiàn)瀑布流分頁滾動加載,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-09-09
  • CodeReview常見的幾個問題梳理解決示例

    CodeReview常見的幾個問題梳理解決示例

    這篇文章主要為大家介紹了CodeReview常見的幾個問題梳理解決,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-12-12
  • JavaScript 克隆數(shù)組最簡單的方法

    JavaScript 克隆數(shù)組最簡單的方法

    js 樹組復(fù)制方法
    2009-02-02
  • uniapp使用H5調(diào)試時跨域問題解決

    uniapp使用H5調(diào)試時跨域問題解決

    本文主要介紹了uniapp使用H5調(diào)試時跨域問題解決,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2022-07-07
  • 詳解小程序不同頁面之間通訊的解決方案

    詳解小程序不同頁面之間通訊的解決方案

    這篇文章主要介紹了詳解小程序不同頁面之間通訊的解決方案,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-11-11
  • 詳解處理bootstrap4不支持遠程靜態(tài)框問題

    詳解處理bootstrap4不支持遠程靜態(tài)框問題

    這篇文章主要介紹了詳解處理bootstrap4不支持遠程靜態(tài)框問題,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-07-07
  • 如何使用瀏覽器擴展篡改網(wǎng)頁中的JS?文件

    如何使用瀏覽器擴展篡改網(wǎng)頁中的JS?文件

    這篇文章主要為大家介紹了如何使用瀏覽器擴展篡改網(wǎng)頁中的JS文件實現(xiàn)解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-05-05

最新評論