波多野吉不卡中文Av无码Av

      <strong id="fzzds"><track id="fzzds"></track></strong>
    1. <strong id="fzzds"></strong>
      <strong id="fzzds"></strong>
    2. <ruby id="fzzds"><bdo id="fzzds"><rp id="fzzds"></rp></bdo></ruby>
        <strike id="fzzds"></strike>
      1. 您現在的位置: 微信小程序 > 微信小程序運營 > 經驗 >

        我是如何寫超大型小程序代碼的?

        來源:微信小程序 編輯:Yiyongtong.com 發布時間:2020-05-18 10:28熱度:

        你 和一頭駱駝準備穿過沙漠,前面是一眼望不到頭的沙海,你的目的是要穿過 沙漠到達對面的綠洲。 現在你寫的每一行代碼就是往駱駝上負重。 當然,有些 負重是 必須 的,比如水和食物。

        可能會由于負重太多,駱駝嚴重拖累行程,甚至可能永遠走不出沙漠。

        可能水和食物不夠,都被餓死在中途。

        本文目錄:

        • 有必要重申的交互原理

        • 請慎重設置 data

        • 請三思組件間如何通信

        • 友好的使用 sass

        • 不可或缺的 template & @import

        • 理解多頁應用的單頁應用

        • 第三方庫

        • 請善待主包

            小程序有包大小限制,單個主包或者子包不能超過 2M,總包不能高于 12M。

        有大小限制,那么對于超大型小程序,就要悠著點了,否則超包那就是家常便飯了,當然小程序這個遠不及瀏覽器的內存和性能也提醒著我們要悠著點。

        現在,請開始給駱駝負重?。?!

        有必要重申的交互原理

        小程序的 Page 給我們提供了一個 data 對象。這個 data 對象的數據更新,則直接影響 wxml 的內容。有 vue 或者 react 開發經驗的同學可能再熟悉不過了。當然小程序我們需要使用 setData 來更新數據。

        Page({
          data: {
            text: "This is page data."
          },
          onLoad: function(options) {
            // doSomething
          }
        });
        

        這是官網上的描述:

        小程序的視圖層目前使用 WebView 作為渲染載體,而邏輯層是由獨立的 JavascriptCore 作為運行環境。在架構上,WebView 和 JavascriptCore 都是獨立的模塊,并不具備數據直接共享的通道。當前,視圖層和邏輯層的數據傳輸,實際上通過兩邊提供的 evaluateJavascript 所實現。即用戶傳輸的數據,需要將其轉換為字符串形式傳遞,同時把轉換后的數據內容拼接成一份 JS 腳本,再通過執行 JS 腳本的形式傳遞到兩邊獨立環境。

        簡而言之,js 邏輯層的 data 的數據是需要轉換成字符串,再使用 JS 腳本傳輸到 wxml 的視圖層。文檔也明確了傳輸不實時。實際上如果數據量大還很慢。

        請慎重設置 data

        data 對象是類似 vue 的 data,是 reactivity 的。vue 的 reactivity 的數據,是都需要 Object.defineProperty(或者 Proxy)的。

        比如看到有代碼,在 data 里面放大量的數據,而這些數據根本上在 wxml 里面用不上,僅僅是為了存儲一個對象,在其他文件模塊(同 this)的時候,能直接用。還看到在 data 里面設置 isLoading 對象,這個僅僅是為了在點擊的時候做一個鎖,等接口調用完成,再把 isLoading 改為 false。

        以上情況,在小程序代碼中比比皆是。這些都有一個通病,忽略了性能,隨心使用 data,導致一個頁面,在 data 下設置的變量可能占滿一屏的高度。

        那我們如何做呢?

        原則:只在 data 對象設置在 wxml 需要使用的變量。

        那么其他變量我們怎么做呢?有兩種方案:

        1、設置在實例作用域外,脫離 Page 或者 Component 對象。

        let name = "is file scope data";
        Page({});
        

        2、設置在實例作用域內,但是脫離 data 對象,不需要 reactivity。

        a) 如果是 Page ,可以直接新增一個 customData,

        Page({
            data:{
                name:"reactivity data"
            },
            customData: {
                name: 'not reactivity data'
            }.
        });
        

        b) 如果是 Component,可以使用 pureData。

        Component({
        options: {
          pureDataPattern: /^_/ // 指定所有 _ 開頭的數據字段為純數據字段
        },
        data: {
          name: "is reactivity",
          _name: "is pureData",
        },
        

        經過實驗證明,對于邏輯復雜,數據量大的頁面,很好的優化你的 data,對性能提升比較明顯。

        請三思組件間如何通信

        組件間通信方式:

        1. 子組件向父組件:triggerEvent

        2. 父組件向子組件:props

        3. 父組件向子組件:selectComponent

        4. 訂閱發布模式:emit、on

        當前前三者,都是小程序直接提供的方式,第四種我們需要寫一個公共的 emitter 組件。下面我們來分析下這種情況。

        1.triggerEvent

        子組件向父組件通信,這種在開發中非常常見,子組件響應了操作,如果需要同步給父組件,直接用 this.triggerEvent,然后在父組件中定義 bind 就行。

        2. props

        父組件向子組件傳參,這種也非常常見,如果你需要傳參給子組件,需要做如下兩步:

        1、父組件需要在 reactivity 的 data 中設置數據;

        2、子組件需要在 props 屬性中設置接收該數據對象。

        發現沒有,如果你需要傳一個參數,那么你需要在父子組件當中都設置為 reactivity 的 data 對象。顯然,對于大量的傳輸數據對象(比如一個大型數據列表),不適合直接這樣傳參。因為如果這樣做的話,顯然增大了父子組件成本。

        3. selectComponent

        父組件直接調用子組件實例對象,然后直接執行子組件的方法,比如:

        子組件:

        Component({
          methods: {
            updateStatus() {}
          }
        });
        

        父組件:

        this.selectComponent("#childComponent").updateStatus();
        

        selectComponent,完美的解決了 props 傳參的問題,微信給你另一條道路,也說明了 props 的問題。但是 props 傳參方式更符合開發習慣和數據流思維。

        個人建議,大數據傳輸,直接用 selectComponent,反之用 props。

        4. $emit

        發布訂閱模式,大伙都很熟悉了。注冊 on("key", () => {}),發布 emit("key", data)。這種方式的優點很明顯,完全突破組件直接的關系。任何地方都可以監聽,都可以發布。

        缺點則是無狀態的,和組件實例無關,且是全局的。

        如果頁面打開了兩個 Page,比如 商祥 -> 店鋪 -> 商祥 ,這個時候,如果商詳接受到一個消息,兩個商祥 Page 都會收到。

        發布訂閱模式需要注意四點:

        1. key 是全局的,好好命名。

        2. 接收消息的區分是不是該實例的。

        3. 銷毀注冊消息通常是全部的。A 監聽 key,B 監聽 key,如果執行 remove(key),則 key 都會清除。

        4. 如果不支持粘性事件則需要關注發布訂閱時機。

        (當然你可以選擇不把 EventBus 放到全局)

        友好的使用 sass

        樣式文件,我們一般使用預處理,比如 sass。我們看如下例子。

        <view class="recommend">
            <view class="recommend_header">
                <view class="recommend_header_author">
                    <view class="recommend_header_author_img"></view>
                    <view class="recommend_header_author_info">
                        <view class="recommend_header_author_info_name"></view>
                        <view class="recommend_header_author_info_location"></view>
                    </view>
                </view>
                <view class="recommend_header_follow"></view>
            </view>
            <view class="recommend_footer">
            </view>
        </view>
        
        .recommend {
          &_header {
            &_author {
              &_img {
              }
              &_info {
                &_name {
                }
              }
            }
          }
        }
        

        上述結構和樣式,看不出啥,我們經常在 H5 頁面的時候都是如此做的,按照頁面模塊和層級定義結構,使用 sass 逐層寫樣式,這可以說是標準寫法,語義和結構清晰,

        但是在超大型小程序中,我要 say No!

        我們知道,sass 是 css 預處理器,最終是需要轉換成 css 被瀏覽器和微信小程序識別。

        我們看下轉換后的樣式文件

        .recommend {
        }
        .recommend .recommend_header {
        }
        .recommend .recommend_header .recommend_header_author {
        }
        .recommend .recommend_header .recommend_header_author {
        }
        .recommend
          .recommend_header
          .recommend_header_author
          .recommend_header_author_info {
        }
        .recommend
          .recommend_header
          .recommend_header_author
          .recommend_header_author_info
          .recommend_header_author_info_name {
        }
        

        看了之后有沒有覺得你哪里不對?重復的 class 太多了,看到這么多重復的,JS 開發人員第一反應:提煉抽取才是正道。想想我們大幾十行研發人員開發的小程序,功能如此之多,體積如此之珍貴,豈能如此浪費。

        回歸到 sass,我們使用樣式層級作用域的目的是啥呢?我認為無非是絕對標識該樣式,類似 js 的作用域,不被其他模塊的樣式影響,然后能夠清晰的定義樣式。

        試想,如果張三在頁面 header 模塊的用戶昵稱,定義成 .name,那么李四在 content 模塊的用戶昵稱也可能會被定義成 .name,然而這兩個樣式完全不一樣,但是樣式就會相互影響,李四把 .name 樣式寫好了,然而 header 模塊的 .name 樣式又不對了,這顯然不是我們想要的,所以推薦把樣式的名稱按層級定義,不會被影響。

        理由很充分,sass 寫起來也很舒服,但是在實際中極力不推薦嚴格按這種層級定義。

        那么在大型小程序中,推薦: 最多三級,建議兩級。

        對應上述 wxml ,在結構不變的情況下,樣式修正為如下:

        <view class="recommend">
            <view class="recommend_header">
                <view class="recommend_author">
                    <view class="recommend_img"></view>
                    <view class="recommend_info">
                        <view class="recommend_name"></view>
                        <view class="recommend_location"></view>
                    </view>
                </view>
                <view class="recommend_follow"></view>
            </view>
            <view class="recommend_footer">
            </view>
        </view>
        

        有人會說了,這個 header 模塊用戶昵稱可能是 .recommend_name,但是 footer 模塊也有一個用戶昵稱怎么辦?

        通常一個模塊是一個人維護,就算多個人修改,那么樣式也只在當前模塊內影響,風險完全可控。那么 footer 模塊的昵稱可以定義成 .recommend_footer_name,增加到第三層,甚至于我推薦直接是 .recommend_footer-name,這樣在解析成 css 的時候,仍然是兩層。

        都 21 世紀了,總想著再不斷的出現愛因斯坦、牛頓等已經不太現實了。我們要 “微優化”!

        總結:在可讀性仍然很強大的情況下,保證模塊直接樣式不沖突,建議控制在兩層 sass,最多不超過三層。減少文件大小。

        在模塊多的頁面中,這種帶來 wxml 和 css 體積的縮減其實是很可觀的。

        template & @import

        根據頁面劃分組件,大伙都會做。然而實際上在模塊中會存在很多共同的結構,但是有時候我們因為邏輯較少等原因沒必要抽離成一個組件,這個時候 template 就派上大用場了。

        單個文件中的共同結構

        <template name="liveItem"> </template>
        <template is="liveItem" data="{{list:preLiveList}}" />
        <template is="liveItem" data="{{list:liveList}}" />
        

        多個模塊中的共同結構

        <import src="./template.wxml" />
        <template is="goodsItem" data="{{item}}" />
        <template is="goodsItem" data="{{item}}" />
        

        當然,wxml 抽離成模塊引入了,那么 css 自然也需要抽離成公共的文件。

        @import "../../common/common.wxss";
        

        按照經驗,一個呈現稍微復雜一點的頁面,如果沒有存在 template 和 公共引入 css 文件,大概率重復代碼不少。當然,如果你很樂意把組件拆的足夠細的話(component 渲染性能慢的問題指南),那么也是可以規避這個問題,但是實際上可能有些代碼量反而還增多了, 合理 template 才是正確姿勢。

        理解多頁應用的單頁應用

        小程序是一個多頁面應用,各個模塊獨立開發,整個系統是多個 Pages 組成的,但是和我們常規的 H5 不同,訪問多個頁面之后,這些頁面是共存的。

        訪問 A 頁面 -> 訪問 B 頁面,此時 A 頁面是仍然在運行,只不過是 hide 的。

        既然多個頁面都存在,但是當前 active 的只有一個頁面,因此我們仍然要做一些單頁面應用需要做的事,比如:

        1、停止更新數據 直播的點贊動畫,如果當前頁面不是 onShow 的,就不要去更新動畫了,節省點 CPU 吧!

        2、及時回收定時器 在 A 頁面開啟了定時器,顯示倒計時,但是到 B 頁面了,A 頁面的倒計時就沒有意義了,應該及時回收和清除。當然如果你需要在頁面返回到 A 頁面的時候,仍然能看到倒計時,那么請在 onShow 的時候喚醒倒計時,onHide 的時候清除倒計時。只管利用,不善后的可不是好學生哦!

        3、及時清除不必要的資源。當前訪問 A 頁面,然后返回,再次訪問 A 頁面,那么頁面的非實例對象數據是不會清除的,我們需要手動清除對象,釋放資源,防止重復注冊等操作。

        第三方庫

        第三方庫用起來爽呀,一個看起來不簡單的三下五除二就搞定了,能不爽嗎?

        比如我們使用 vue 開發頁面,有輪播圖,引用第三方 swiper,我們需要做時間處理,引用 moment。

        本人開發這么多頁面和系統,這些組件很少引用,我的做法是明確我的需求,如果有類似的,然后不會寫的,那么閱讀下源碼,自己寫下就行。因為我知道,開發的組件都是支持最全面的,實際上你根本不需要這么多,比如格式化時間,你的需求可能就是實際十幾行代碼的事情,為啥要引入一個第三方組件呢?同理一個 swiper,別人支持的各種各種需求,你的可能只是需要普通的滑動切換就行了,為啥要引入強大的第三方組件呢?

        當然如果第三方組件可以支持良好的 tree-shaking 就另當別論。

        在 H5 時代,我一般不輕易引入第三方庫,對于他人代碼我也是持保留意見。

        但是在大型小程序時代,我是堅決反對用啥直接引用啥。畢竟 【體積 & 內存 & 性能】三座大山擺在眼前。

        請善待主包

        如果直接打開子包鏈接,那么是需要下載 主包 + 當前子包,然后才能訪問頁面。那么主包的下載對頁面首屏的打開,就顯得至關重要了。

        按照我們 H5 開發的邏輯,公共代碼都需要抽離成獨立的模塊,方便共用。但是小程序場景有點不一樣。

        A 子包 require goodsModule

        B 子包 require goodsModule

        這個時候,將 goodsModule 抽離出來,放在主包(因為子包直接相互引用的問題)??雌饋硪磺许樒渥匀?。

        然而,如果你遵循上面的方案,那么你會發現,在超大型的小程序中,會有大量的 Modules 被放到主包,導致主包嚴重不足。那如何解決這個問題?我們可以使用 NPM 功能。

        思想仍然會是模塊單獨下載,訪問了 A 頁面,下載 A 子包,然后再訪問 B 頁面,下載 B 子包。盡管 A 和 B 子包有重復下載的代碼。

        那什么情況放在主包呢?

        1、主包 Pages 已經有引用了

        2、至少有三個及以上的子包引用同樣的模塊

        善待主包,兼顧總包!

        波多野吉不卡中文Av无码Av

          <strong id="fzzds"><track id="fzzds"></track></strong>
        1. <strong id="fzzds"></strong>
          <strong id="fzzds"></strong>
        2. <ruby id="fzzds"><bdo id="fzzds"><rp id="fzzds"></rp></bdo></ruby>
            <strike id="fzzds"></strike>