日本XXXX裸体XXXX在线观看,乱中年女人伦AV一区二区,色狠狠一区二区三区熟女

  • <em id="d9ukz"><acronym id="d9ukz"><input id="d9ukz"></input></acronym></em>
  • 近兩萬字小程序攻略發布了

    來源:掘金
    2021-02-27
    1044
    導語:該內容由銀科控股融匯研發部曹俊及其團隊授權提供。該團隊擁有 10 多名小程序開發,深耕小程序領域,總結出了本篇優質長文。同時本篇內容也已經合并入我的 開源項目 中,目前項目內容包含了 JS、網絡、瀏覽器相關、性能優化、安全、框架、Git、數據結構、算法等內容,無論是基礎還是進階,亦或是源碼解讀,你都能在本圖譜中得到滿意的答案,希望這個面試圖譜能夠幫助到大家更好的準備面試。
    閱讀本文大概需要15分鐘

    小程序-登錄

    unionid和openid

    了解小程序登陸之前,我們寫了解下小程序/公眾號登錄涉及到兩個最關鍵的用戶標識:

    • OpenId 是一個用戶對于一個小程序/公眾號的標識,開發者可以通過這個標識識別出用戶。
    • UnionId 是一個用戶對于同主體微信小程序/公眾號/APP的標識,開發者需要在微信開放平臺下綁定相同賬號的主體。開發者可通過UnionId,實現多個小程序、公眾號、甚至APP 之間的數據互通了。

    關鍵Api

    登錄流程設計

    以下從筆者接觸過的幾種登錄流程來做闡述:

    利用現有登錄體系

    直接復用現有系統的登錄體系,只需要在小程序端設計用戶名,密碼/驗證碼輸入頁面,便可以簡便的實現登錄,只需要保持良好的用戶體驗即可。

    利用OpenId 創建用戶體系

    ?提過,OpenId 是一個小程序對于一個用戶的標識,利用這一點我們可以輕松的實現一套基于小程序的用戶體系,值得一提的是這種用戶體系對用戶的打擾最低,可以實現靜默登錄。具體步驟如下:

    1. 小程序客戶端通過 wx.login 獲取 code

    2. 傳遞 code 向服務端,服務端拿到 code 調用微信登錄憑證校驗接口,微信服務器返回 openid 和會話密鑰 session_key ,此時開發者服務端便可以利用 openid 生成用戶入庫,再向小程序客戶端返回自定義登錄態

    3. 小程序客戶端緩存 (通過storage)自定義登錄態(token),后續調用接口時攜帶該登錄態作為用戶身份標識即可

    利用 Unionid 創建用戶體系

    如果想實現多個小程序,公眾號,已有登錄系統的數據互通,可以通過獲取到用戶 unionid 的方式建立用戶體系。因為 unionid 在同一開放平臺下的所所有應用都是相同的,通過 unionid 建立的用戶體系即可實現全平臺數據的互通,更方便的接入原有的功能,那如何獲取 unionid 呢,有以下兩種方式:

    1. 如果戶關注了某個相同主體公眾號,或曾經在某個相同主體App、公眾號上進行過微信登錄授權,通過 wx.login 可以直接獲取 到 unionid

    2. 結合 wx.getUserInfo

    注意事項

    1. 需要獲取 unionid 形式的登錄體系,在以前(18年4月之前)是通過以下這種方式來實現,但后續微信做了調整(因為一進入小程序,主動彈起各種授權彈窗的這種形式,比較容易導致用戶流失),調整為必須使用按鈕引導用戶主動授權的方式,這次調整對開發者影響較大,開發者需要注意遵守微信的規則,并及時和業務方溝通業務形式,不要存在僥幸心理,以防造成小程序不過審等情況。
       wx.login(獲取code) ===> wx.getUserInfo(用戶授權) ===> 獲取 unionid
    復制代碼
    1. 因為小程序不存在 cookie 的概念, 登錄態必須緩存在本地,因此強烈建議為登錄態設置過期時間

    2. 值得一提的是如果需要支持風控安全校驗,多平臺登錄等功能,可能需要加入一些公共參數,例如platform,channel,deviceParam等參數。在和服務端確定方案時,作為前端同學應該及時提出這些合理的建議,設計合理的系統。

    3. openid , unionid 不要在接口中明文傳輸,這是一種危險的行為,同時也很不專業。

    小程序-圖片導出

    經常開發和使用小程序的同學對這個功能一定不陌生,這是一種常見的引流方式,一般同時會在圖片中附加一個小程序二維碼。

    基本原理

    1. 借助 canvas 元素,將需要導出的樣式首先在 canvas 畫布上繪制出來 (api基本和h5保持一致,但有輕微差異,使用時注意即可)

    2. 借助微信提供的 canvasToTempFilePath 導出圖片,最后再使用 saveImageToPhotosAlbum (需要授權)保存圖片到本地

    如何優雅實現

    根據上述的原理來看,實現是很簡單的,只不過就是設計稿的提取,繪制即可,但是作為一個常用功能,每次都這樣寫一坨代碼豈不是非常的難受。那小程序如何設計一個通用的方法來幫助我們導出圖片呢?思路如下:

    1. 繪制出需要的樣式這一步是省略不掉的。但是我們可以封裝一個繪制庫,包含常見圖形的繪制,例如矩形,圓角矩形,圓, 扇形, 三角形, 文字,圖片減少繪制代碼,只需要提煉出樣式信息,便可以輕松的繪制,最后導出圖片存入相冊。筆者覺得以下這種方式繪制更為優雅清晰一些,其實也可以使用加入一個type參數來指定繪制類型,傳入的一個是樣式數組,實現繪制。

    2. 結合上一步的實現,如果對于同一類型的卡片有多次導出需求的場景,也可以使用自定義組件的方式,封裝同一類型的卡片為一個通用組件,在需要導出圖片功能的地方,引入該組件即可。

        
      class CanvasKit {
        constructor() {
        }
        drawImg(option = {}) {
          ...
          return this
        }
        drawRect(option = {}) {
          return this
        }
        drawText(option = {}) {
          ...
          return this
        }
        static exportImg(option = {}) {
          ...
        }
      }
    
      let drawer = new CanvasKit('canvasId').drawImg(styleObj1).drawText(styleObj2)
      drawer.exportImg()
    
    復制代碼

    注意事項

    1. 小程序中無法繪制網絡圖片到canvas上,需要通過downLoadFile 先下載圖片到本地臨時文件才可以繪制
    2. 通常需要繪制二維碼到導出的圖片上,有一種方式導出二維碼時,需要攜帶的參數必須做編碼,而且有具體的長度(32可見字符)限制,可以借助服務端生成 短鏈接 的方式來解決

    小程序-數據統計

    數據統計作為目前一種常用的分析用戶行為的方式,小程序端也是必不可少的。小程序采取的曝光,點擊數據埋點其實和h5原理是一樣的。但是埋點作為一個和業務邏輯不相關的需求,我們如果在每一個點擊事件,每一個生命周期加入各種埋點代碼,則會干擾正常的業務邏輯,和使代碼變的臃腫,筆者提供以下幾種思路來解決數據埋點:

    設計一個埋點sdk

    小程序的代碼結構是,每一個 Page 中都有一個 Page 方法,接受一個包含生命周期函數,數據的 業務邏輯對象 包裝這層數據,借助小程序的底層邏輯實現頁面的業務邏輯。通過這個我們可以想到思路,對Page進行一次包裝,篡改它的生命周期和點擊事件,混入埋點代碼,不干擾業務邏輯,只要做一些簡單的配置即可埋點,簡單的代碼實現如下:

      
      代碼僅供理解思路
      page = function(params) {
        let keys = params.keys()
        keys.forEach(v => {
            if (v === 'onLoad') {
              params[v] = function(options) {
                stat()   //曝光埋點代碼
                params[v].call(this, options)
              }
            }
            else if (v.includes('click')) {
              params[v] = funciton(event) { 
                let data = event.dataset.config
                stat(data)  // 點擊埋點
                param[v].call(this)
              }
            }
        })
      }
    復制代碼

    這種思路不光適用于埋點,也可以用來作全局異常處理,請求的統一處理等場景。

    分析接口

    對于特殊的一些業務,我們可以采取 接口埋點,什么叫接口埋點呢?很多情況下,我們有的api并不是多處調用的,只會在某一個特定的頁面調用,通過這個思路我們可以分析出,該接口被請求,則這個行為被觸發了,則完全可以通過服務端日志得出埋點數據,但是這種方式局限性較大,而且屬于分析結果得出過程,可能存在誤差,但可以作為一種思路了解一下。

    微信自定義數據分析

    微信本身提供的數據分析能力,微信本身提供了常規分析和自定義分析兩種數據分析方式,在小程序后臺配置即可。借助小程序數據助手這款小程序可以很方便的查看。

    小程序-工程化

    工程化做什么

    目前的前端開發過程,工程化是必不可少的一環,那小程序工程化都需要做些什么呢,先看下目前小程序開發當中存在哪些問題需要解決:

    1. 不支持 css預編譯器,作為一種主流的 css解決方案,不論是 less,sass,stylus 都可以提升css效率
    2. 不支持引入npm包 (這一條,從微信公開課中聽聞,微信準備支持)
    3. 不支持ES7等后續的js特性,好用的async await等特性都無法使用
    4. 不支持引入外部字體文件,只支持base64
    5. 沒有 eslint 等代碼檢查工具

    方案選型

    對于目前常用的工程化方案,webpack,rollup,parcel等來看,都常用與單頁應用的打包和處理,而小程序天生是 “多頁應用” 并且存在一些特定的配置。根據要解決的問題來看,無非是文件的編譯,修改,拷貝這些處理,對于這些需求,我們想到基于流的 gulp非常的適合處理,并且相對于webpack配置多頁應用更加簡單。所以小程序工程化方案推薦使用 gulp

    具體開發思路

    通過 gulp 的 task 實現:

    1. 實時編譯 less 文件至相應目錄
    2. 引入支持async,await的運行時文件
    3. 編譯字體文件為base64 并生成相應css文件,方便使用
    4. 依賴分析哪些地方引用了npm包,將npm包打成一個文件,拷貝至相應目錄
    5. 檢查代碼規范

    上述實現起來其實并不是很難,但是這樣的話就是一份純粹的 gulp 構建腳本和 約定好的目錄而已,每次都有一個新的小程序都來拷貝這份腳本來處理嗎?顯然不合適,那如何真正的實現 小程序工程化 呢? 我們可能需要一個簡單的腳手架,腳手架需要支持的功能:

    1. 支持新建項目,創建Page,創建Component
    2. 支持內置構建腳本
    3. 支持發布小程序,也可以想辦法接入Jenkins等工具做持續集成 (小程序持續集成后面會提) ...

    小程序架構

    architecture">

    微信小程序的框架包含兩部分 View 視圖層、App Service邏輯層。View 層用來渲染頁面結構,AppService 層用來邏輯處理、數據請求、接口調用。

    它們在兩個線程里運行。

    它們在兩個線程里運行。

    它們在兩個線程里運行。

    視圖層和邏輯層通過系統層的 JSBridage 進行通信,邏輯層把數據變化通知到視圖層,觸發視圖層頁面更新,視圖層把觸發的事件通知到邏輯層進行業務處理。

    補充

    one-context

    視圖層使用 WebView 渲染,iOS 中使用自帶 WKWebView,在 Android 使用騰訊的 x5 內核(基于 Blink)運行。

    邏輯層使用在 iOS 中使用自帶的 JSCore 運行,在 Android 中使用騰訊的 x5 內核(基于 Blink)運行。

    開發工具使用 nw.js 同時提供了視圖層和邏輯層的運行環境。

    在 Mac下 使用 js-beautify 對微信開發工具 @v1.02.1808080代碼批量格式化:

    cd /Applications/wechatwebdevtools.app/Contents/Resources/package.nw
    find . -type f -name '*.js' -not -path "./node_modules/*" -not -path -exec js-beautify -r -s 2 -p -f '{}' \;
    復制代碼

    js/extensions/appservice/index.js 中找到:

    	267: function(a, b, c) {
        const d = c(8),
          e = c(227),
          f = c(226),
          g = c(228),
          h = c(229),
          i = c(230);
        var j = window.__global.navigator.userAgent,
          k = -1 !== j.indexOf('game');
        k || i(), window.__global.getNewWeixinJSBridge = (a) => {
          const {
            invoke: b
          } = f(a), {
            publish: c
          } = g(a), {
            subscribe: d,
            triggerSubscribeEvent: i
          } = h(a), {
            on: j,
            triggerOnEvent: k
          } = e(a);
          return {
            invoke: b,
            publish: c,
            subscribe: d,
            on: j,
            get __triggerOnEvent() {
              return k
            },
            get __triggerSubscribeEvent() {
              return i
            }
          }
        }, window.WeixinJSBridge = window.__global.WeixinJSBridge = window.__global.getNewWeixinJSBridge('global'), window.__global.WeixinJSBridgeMap = {
          __globalBridge: window.WeixinJSBridge
        }, __devtoolsConfig.online && __devtoolsConfig.autoTest && setInterval(() => {
          console.clear()
        }, 1e4);
        try {
          var l = new window.__global.XMLHttpRequest;
          l.responseType = 'text', l.open('GET', `http://${window.location.host}/calibration/${Date.now()}`, !0), l.send()
        } catch (a) {}
      }
    復制代碼

    js/extensions/gamenaitveview/index.js 中找到:

      299: function(a, b, c) {
        'use strict';
        Object.defineProperty(b, '__esModule', {
          value: !0
        });
        var d = c(242),
          e = c(241),
          f = c(243),
          g = c(244);
        window.WeixinJSBridge = {
          on: d.a,
          invoke: e.a,
          publish: f.a,
          subscribe: g.a
        }
      },
    復制代碼

    js/extensions/pageframe/index.js中找到:

    317: function(a, b, c) {
        'use strict';
    
        function d() {
          window.WeixinJSBridge = {
            on: e.a,
            invoke: f.a,
            publish: g.a,
            subscribe: h.a
          }, k.a.init();
          let a = document.createEvent('UIEvent');
          a.initEvent('WeixinJSBridgeReady', !1, !1), document.dispatchEvent(a), i.a.init()
        }
        Object.defineProperty(b, '__esModule', {
          value: !0
        });
        var e = c(254),
          f = c(253),
          g = c(255),
          h = c(256),
          i = c(86),
          j = c(257),
          k = c.n(j);
        'complete' === document.readyState ? d() : window.addEventListener('load', function() {
          d()
        })
      },
    復制代碼

    我們都看到了 WeixinJSBridge 的定義。分別都有 on、invoke、publish、subscribe 這個幾個關鍵方法。

    invoke 舉例,在 js/extensions/appservice/index.js中發現這段代碼:

    f (!r) p[b] = s, f.send({
        command: 'APPSERVICE_INVOKE',
        data: {
            api: c,
            args: e,
            callbackID: b
        }
    });
    復制代碼

    js/extensions/pageframe/index.js 中發現這段代碼:

    g[d] = c, e.a.send({
        command: 'WEBVIEW_INVOKE',
        data: {
            api: a,
            args: b,
            callbackID: d
        }
    })
    
    復制代碼

    簡單的分析得知:字段 command 用來區分行為,invoke 用來調用 Native 的 Api。在不同的來源要使用不同的前綴。data 里面包含 Api 名,參數。另外 callbackID 指定接受回調的方法句柄。Appservice 和 Webview 使用的通信協議是一致的。

    我們不能在代碼里使用 BOM 和 DOM 是因為根本沒有,另一方面也不希望 JS 代碼直接操作視圖。

    在開發工具中 remote-helper.js 中找到了這樣的代碼:

    const vm = require("vm");
    
    const vmGlobal = {
        require: undefined,
        eval: undefined,
        process: undefined,
        setTimeout(...args) {
            //...省略代碼
            return timerCount;
        },
        clearTimeout(id) {
            const timer = timers[id];
            if (timer) {
                clearTimeout(timer);
                delete timers[id];
            }
        },
        setInterval(...args) {
            //...省略代碼
            return timerCount;
        },
        clearInterval(id) {
            const timer = timers[id];
            if (timer) {
                clearInterval(timer);
                delete timers[id];
            }
        },
        console: (() => {
            //...省略代碼
            return consoleClone;
        })()
    };
    const jsVm = vm.createContext(vmGlobal);
    // 省略大量代碼...
    function loadCode(filePath, sourceURL, content) {
        let ret;
        try {
            const script = typeof content === 'string' ? content : fs.readFileSync(filePath, 'utf-8').toString();
            ret = vm.runInContext(script, jsVm, {
                filename: sourceURL,
            });
        }
        catch (e) {
            // something went wrong in user code
            console.error(e);
        }
        return ret;
    }
    復制代碼

    這樣的分層設計顯然是有意為之的,它的中間層完全控制了程序對于界面進行的操作, 同時對于傳遞的數據和響應時間也能做到監控。一方面程序的行為受到了極大限制, 另一方面微信可以確保他們對于小程序內容和體驗有絕對的控制。

    這樣的結構也說明了小程序的動畫和繪圖 API 被設計成生成一個最終對象而不是一步一步執行的樣子, 原因就是 Json 格式的數據傳遞和解析相比與原生 API 都是損耗不菲的,如果頻繁調用很可能損耗過多性能,進而影響用戶體驗。

    下載小程序完整包

    download">

    App Service - Life Cylce

    lifecycle">

    面試題

    1.動畫需要綁定在 data 上,而繪圖卻不用。你覺得是為什么呢?

    var context = wx.createCanvasContext('firstCanvas')
        
    context.setStrokeStyle("#00ff00")
    context.setLineWidth(5)
    context.rect(0, 0, 200, 200)
    context.stroke()
    context.setStrokeStyle("#ff0000")
    context.setLineWidth(2)
    context.moveTo(160, 100)
    context.arc(100, 100, 60, 0, 2 * Math.PI, true)
    context.moveTo(140, 100)
    context.arc(100, 100, 40, 0, Math.PI, false)
    context.moveTo(85, 80)
    context.arc(80, 80, 5, 0, 2 * Math.PI, true)
    context.moveTo(125, 80)
    context.arc(120, 80, 5, 0, 2 * Math.PI, true)
    context.stroke()
    context.draw()
    復制代碼
    Page({
      data: {
        animationData: {}
      },
      onShow: function(){
        var animation = wx.createAnimation({
          duration: 1000,
      	  timingFunction: 'ease',
        })
    
        this.animation = animation
        
        animation.scale(2,2).rotate(45).step()
        
        this.setData({
          animationData:animation.export()
        })
      }
    })
    復制代碼

    2.小程序的 Http Rquest 請求是不是用的瀏覽器 Fetch API?

    知識點考察

    • 知道 Request 是由 Native 實現的
    • JSCore 是不帶 Http Request、Websocket、Storage等功能的,那是 Webkit 帶的
    • 小程序的 wx.request 是不是遵循 fetch API 規范實現的呢?答案,顯然不是。因為沒有 Promise

    View - WXML

    WXML(WeiXin Markup Language)

    • 支持數據綁定
    • 支持邏輯算術、運算
    • 支持模板、引用
    • 支持添加事件(bindtap)

    WXML">

    Wxml編譯器:Wcc 把 Wxml文件 轉為 JS

    執行方式:Wcc index.wxml

    使用 Virtual DOM,進行局部更新

    View - WXSS

    WXSS(WeiXin Style Sheets)

    WXSS">

    wxss編譯器:wcsc 把wxss文件轉化為 js

    執行方式: wcsc index.wxss

    支持大部分CSS特性

    親測包含但不限于如下內容:

    • Transition
    • Animation
      • Keyframes
    • border-radius
    • calc()
    • 選擇器,除了官方文檔列出的,其實還支持
      • element>element
      • element+element
      • element element
      • element:first-letter
      • element:first-line
      • element:first-child
      • element:last-child
      • element~element
      • element:first-of-type
      • element:last-of-type
      • element:only-of-type
      • element:only-child
      • element:nth-child(n)
      • element:nth-last-child(n)
      • element:nth-of-type(n)
      • element:nth-last-of-type(n)
      • :root
      • element:empty
      • :not(element)
    • iconfont

    建議 Css3 的特性都可以做一下嘗試。

    尺寸單位 rpx

    rpx(responsive pixel): 可以根據屏幕寬度進行自適應。規定屏幕寬為 750rpx。公式:

    const dsWidth = 750
    
    export const screenHeightOfRpx = function () {
      return 750 / env.screenWidth * env.screenHeight
    }
    
    export const rpxToPx = function (rpx) {
      return env.screenWidth / 750 * rpx
    }
    
    export const pxToRpx = function (px) {
      return 750 / env.screenWidth * px
    }
    
    復制代碼
    設備 rpx換算px (屏幕寬度/750) px換算rpx (750/屏幕寬度)
    iPhone5 1rpx = 0.42px 1px = 2.34rpx
    iPhone6 1rpx = 0.5px 1px = 2rpx
    iPhone6 Plus 1rpx = 0.552px 1px = 1.81rpx

    可以了解一下 pr2rpx-loader 這個庫。

    樣式導入

    使用 @import語句可以導入外聯樣式表,@import后跟需要導入的外聯樣式表的相對路徑,用 ; 表示語句結束。

    內聯樣式

    靜態的樣式統一寫到 class 中。style 接收動態的樣式,在運行時會進行解析,請盡量避免將靜態的樣式寫進 style 中,以免影響渲染速度。

    全局樣式與局部樣式

    定義在 app.wxss 中的樣式為全局樣式,作用于每一個頁面。在 page 的 wxss 文件中定義的樣式為局部樣式,只作用在對應的頁面,并會覆蓋 app.wxss 中相同的選擇器。

    iconfont

    截止20180810

    小程序未來有計劃支持字體。參考微信公開課。

    小程序開發與平時 Web開發類似,也可以使用字體圖標,但是 src:url() 無論本地還是遠程地址都不行,base64 值則都是可以顯示的。

    將 ttf 文件轉換成 base64。打開這個平臺 transfonter.org/。點擊 Add fonts 按鈕,加載ttf格式的那個文件。將下邊的 base64 encode 改為 on。點擊 Convert 按鈕進行轉換,轉換后點擊 download 下載。

    復制下載的壓縮文件中的 stylesheet.css 的內容到 font.wxss ,并且將 icomoon 中的 style.css 除了 @font-face 所有的代碼也復制到 font.wxss 并將i選擇器換成 .iconfont,最后:

    <text class="iconfont icon-home" style="font-size:50px;color:red">text>
    復制代碼

    View - Component

    小程序提供了一系列組件用于開發業務功能,按照功能與HTML5的標簽進行對比如下:

    Component">

    小程序的組件基于Web Component標準

    使用Polymer框架實現Web Component

    View - Native Component

    目前Native實現的組件有

    • cavnas

    • video

    • map

    • textarea

      Native Component

    Native組件層在 WebView 層之上。這目前帶來了一些問題:

    • Native 實現的組件會遮擋其他組件
    • WebView 渲染出來的視圖在滾動時,Native 實現的組件需要更新位置,這會帶來性能問題,在安卓機器上比較明顯
    • 小程序原生組件 cover-view 可以覆蓋 cavnas video 等,但是也有一下弊端,比如在 cavnas 上覆蓋 cover-view,就會發現坐標系不統一處理麻煩

    目前小程序的問題或限制

    截止20180810

    包含但不限于:

    • 小程序仍然使用 WebView 渲染,并非原生渲染。(部分原生)

    • 服務端接口返回的頭無法執行,比如:Set-Cookie。

    • 依賴瀏覽器環境的 JS 庫不能使用。

    • 不能使用 npm,但是可以自搭構建工具或者使用 mpvue。(未來官方有計劃支持)

    • 不能使用 ES7,可以自己用babel+webpack自搭或者使用 mpvue。

    • 不支持使用自己的字體(未來官方計劃支持)。

    • 可以用 base64 的方式來使用 iconfont。

    • 小程序不能發朋友圈(可以通過保存圖片到本地,發圖片到朋友前。二維碼可以使用B接口)。

    • 獲取二維碼/小程序接口的限制。

      • B 接口 scene 最大32個可見字符。
      • AC 接口總共生成的碼數量限制為 100,000,請謹慎調用。
      • 真機掃描二維碼只能跳轉到線上版本,所以測試環境下只可通過開發者工具的通過二維碼編譯進行調試。
      • 沒有發布到線上版本的小程序頁面路徑會導致生成二維碼失敗,需要先將添加了頁面的小程序發布到線上版本。
    • 小程序推送只能使用“服務通知” 而且需要用戶主動觸發提交 formId,formId 只有7天有效期。(現在的做法是在每個頁面都放入form并且隱藏以此獲取更多的 formId。后端使用原則為:優先使用有效期最短的)

    • 小程序大小限制 2M,分包總計不超過 8M

    • 轉發(分享)小程序不能拿到成功結果,原來可以。鏈接(小游戲造的孽)

    • 拿到相同的 unionId 必須綁在同一個開放平臺下。開放平臺綁定限制:

      • 50個移動應用
      • 10個網站
      • 50個同主體公眾號
      • 5個不同主體公眾號
      • 50個同主體小程序
      • 5個不同主體小程序
    • 公眾號關聯小程序,鏈接

      • 所有公眾號都可以關聯小程序。
      • 一個公眾號可關聯10個同主體的小程序,3個不同主體的小程序。
      • 一個小程序可關聯500個公眾號。
      • 公眾號一個月可新增關聯小程序13次,小程序一個月可新增關聯500次。
    • 一個公眾號關聯的10個同主體小程序和3個非同主體小程序可以互相跳轉

    • 品牌搜索不支持金融、醫療

    • 小程序授權需要用戶主動點擊

    • 小程序不提供測試 access_token

    • 安卓系統下,小程序授權獲取用戶信息之后,刪除小程序再重新獲取,并重新授權,得到舊簽名,導致第一次授權失敗

    • 開發者工具上,授權獲取用戶信息之后,如果清緩存選擇全部清除,則即使使用了wx.checkSession,并且在session_key有效期內,授權獲取用戶信息也會得到新的session_key

    小程序HTTP2支持情況

    HTTP2支持情況:模擬器與真機均不支持

    為了驗證小程序對HTTP的支持適配情況,我找了兩個服務器做測試,一個是網上搜索到支持HTTP2的服務器,一個是我本地起的一個HTTP2服務器。測試中所有請求方法均使用 wx.request。

    1. 網上支持HTTP2的服務器:HTTPs://www.snel.com:443

    2. 在Chrome上查看該服務器為 HTTP2

      WechatIMG11">

    3. 在模擬器上請求該接口,請求頭的HTTP版本為HTTP1.1,模擬器不支持HTTP2

      WechatIMG12">

    4. 由于小程序線上環境需要在項目管理里配置請求域名,而這個域名不是我們需要的請求域名,沒必要浪費一個域名位置,所以打開不驗證域名,TSL 等選項請求該接口,通過抓包工具表現與模擬器相同

      WechatIMG14">

    HTTP2服務器需要對小程序做兼容性適配

    由上可以看出,在真機與模擬器都不支持 HTTP2,但是都是成功請求的,并且 響應頭 里的 HTTP 版本都變成了HTTP1.1 版本,說明服務器對 HTTP1.1 做了兼容性適配。

    1. 本地新啟一個 node 服務器,返回 JSON 為請求的 HTTP 版本

      WechatIMG16">

    2. 如果服務器只支持 HTTP2,在模擬器請求時發生了一個 ALPN 協議的錯誤。并且提醒使用適配 HTTP1

      WechatIMG8">

    3. 當把服務器的 allowHTTP1,設置為 true,并在請求時處理相關相關請求參數后,模擬器能正常訪問接口,并打印出對應的 HTTP 請求版本

      WechatIMG15

    授權獲取用戶信息流程

    • session_key 有有效期,有效期并沒有被告知開發者,只知道用戶越頻繁使用小程序,session_key 有效期越長
    • 在調用 wx.login 時會直接更新 session_key,導致舊 session_key 失效
    • 小程序內先調用 wx.checkSession 檢查登錄態,并保證沒有過期的 session_key 不會被更新,再調用 wx.login 獲取 code。接著用戶授權小程序獲取用戶信息,小程序拿到加密后的用戶數據,把加密數據和 code 傳給后端服務。后端通過 code 拿到 session_key 并解密數據,將解密后的用戶信息返回給小程序

    面試題:先授權獲取用戶信息再 login 會發生什么?

    • 用戶授權時,開放平臺使用舊的 session_key 對用戶信息進行加密。調用 wx.login 重新登錄,會刷新 session_key,這時后端服務從開放平臺獲取到新 session_key,但是無法對老 session_key 加密過的數據解密,用戶信息獲取失敗
    • 在用戶信息授權之前先調用 wx.checkSession 呢?wx.checkSession 檢查登錄態,并且保證 wx.login 不會刷新 session_key,從而讓后端服務正確解密數據。但是這里存在一個問題,如果小程序較長時間不用導致 session_key 過期,則 wx.login 必定會重新生成 session_key,從而再一次導致用戶信息解密失敗。

    性能優化

    我們知道view部分是運行在webview上的,所以前端領域的大多數優化方式都有用。

    我們知道view部分是運行在webview上的,所以前端領域的大多數優化方式都有用。

    我們知道view部分是運行在webview上的,所以前端領域的大多數優化方式都有用。

    加載優化

    preload">

    代碼包的大小是最直接影響小程序加載啟動速度的因素。代碼包越大不僅下載速度時間長,業務代碼注入時間也會變長。所以最好的優化方式就是減少代碼包的大小。

    load-time-series">

    小程序加載的三個階段的表示。

    優化方式

    • 代碼壓縮。
    • 及時清理無用代碼和資源文件。
    • 減少代碼包中的圖片等資源文件的大小和數量。
    • 分包加載。

    首屏加載的體驗優化建議

    • 提前請求: 異步數據請求不需要等待頁面渲染完成。
    • 利用緩存: 利用 storage API 對異步請求數據進行緩存,二次啟動時先利用緩存數據渲染頁面,在進行后臺更新。
    • 避免白屏:先展示頁面骨架頁和基礎內容。
    • 及時反饋:即時地對需要用戶等待的交互操作給出反饋,避免用戶以為小程序無響應。

    使用分包加載優化

    sub-package">

    在構建小程序分包項目時,構建會輸出一個或多個功能的分包,其中每個分包小程序必定含有一個主包,所謂的主包,即放置默認啟動頁面/TabBar 頁面,以及一些所有分包都需用到公共資源/JS 腳本,而分包則是根據開發者的配置進行劃分。

    在小程序啟動時,默認會下載主包并啟動主包內頁面,如果用戶需要打開分包內某個頁面,客戶端會把對應分包下載下來,下載完成后再進行展示。

    優點:

    • 對開發者而言,能使小程序有更大的代碼體積,承載更多的功能與服務
    • 對用戶而言,可以更快地打開小程序,同時在不影響啟動速度前提下使用更多功能

    限制:

    • 整個小程序所有分包大小不超過 8M
    • 單個分包/主包大小不能超過 2M

    原生分包加載的配置 假設支持分包的小程序目錄結構如下:

    ├── app.js
    ├── app.json
    ├── app.wxss
    ├── packageA
    │   └── pages
    │       ├── cat
    │       └── dog
    ├── packageB
    │   └── pages
    │       ├── apple
    │       └── banana
    ├── pages
    │   ├── index
    │   └── logs
    └── utils
    
    復制代碼

    開發者通過在 app.json subPackages 字段聲明項目分包結構:

    {
      "pages":[
        "pages/index",
        "pages/logs"
      ],
      "subPackages": [
        {
          "root": "packageA",
          "pages": [
            "pages/cat",
            "pages/dog"
          ]
        }, {
          "root": "packageB",
          "pages": [
            "pages/apple",
            "pages/banana"
          ]
        }
      ]
    }
    
    復制代碼

    分包原則

    • 聲明 subPackages 后,將按 subPackages 配置路徑進行打包,subPackages 配置路徑外的目錄將被打包到 app(主包) 中
    • app(主包)也可以有自己的 pages(即最外層的 pages 字段
    • subPackage 的根目錄不能是另外一個 subPackage 內的子目錄
    • 首頁的 TAB 頁面必須在 app(主包)內

    引用原則

    • packageA 無法 require packageB JS 文件,但可以 require app、自己 package 內的 JS 文件
    • packageA 無法 import packageB 的 template,但可以 require app、自己 package 內的 template
    • packageA 無法使用 packageB 的資源,但可以使用 app、自己 package 內的資源

    官方即將推出 分包預加載

    preload-sub-package">

    獨立分包

    single-sub-package">

    渲染性能優化

    render">

    • 每次 setData 的調用都是一次進程間通信過程,通信開銷與 setData 的數據量正相關。

    • setData 會引發視圖層頁面內容的更新,這一耗時操作一定時間中會阻塞用戶交互。

    • setData 是小程序開發使用最頻繁,也是最容易引發性能問題的。

    避免不當使用 setData

    • 使用 data 在方法間共享數據,可能增加 setData 傳輸的數據量。。data 應僅包括與頁面渲染相關的數據。
    • 使用 setData 傳輸大量數據,**通訊耗時與數據正相關,頁面更新延遲可能造成頁面更新開銷增加。**僅傳輸頁面中發生變化的數據,使用 setData 的特殊 key 實現局部更新。
    • 短時間內頻繁調用 setData,**操作卡頓,交互延遲,阻塞通信,頁面渲染延遲。**避免不必要的 setData,對連續的setData調用進行合并。
    • 在后臺頁面進行 setData,**搶占前臺頁面的渲染資源。**頁面切入后臺后的 setData 調用,延遲到頁面重新展示時執行。

    one-context">

    避免不當使用onPageScroll

    • 只在有必要的時候監聽 pageScroll 事件。不監聽,則不會派發。
    • 避免在 onPageScroll 中執行復雜邏輯
    • 避免在 onPageScroll 中頻繁調用 setData
    • 避免滑動時頻繁查詢節點信息(SelectQuery)用以判斷是否顯示,部分場景建議使用節點布局橡膠狀態監聽(inersectionObserver)替代

    使用自定義組件

    在需要頻繁更新的場景下,自定義組件的更新只在組件內部進行,不受頁面其他部分內容復雜性影響。

    官方小程序技術能力規劃

    自定義組件2.0

    小程序的幾個頁面間,存在一些相同或是類似的區域,這時候可以把這些區域邏輯封裝成一個自定義組件,代碼就可以重用,或者對于比較獨立邏輯,也可以把它封裝成一個自定義組件,也就是微信去年發布的自定義組件,它讓代碼得到復用、減少代碼量,更方便模塊化,優化代碼架構組織,也使得模塊清晰,后期更好地維護,從而保證更好的性能。

    但微信打算在原來的基礎上推出的自定義組件 2.0,它將擁有更高級的性能:

    • usingComponents 計劃支持全局定義和通配符定義:這意味著不用在每個頁面反復定義,可以批量導入目錄下的所有自定義組件
    • 計劃支持類似 Computed 和 watch 的功能,它能使代碼邏輯更清晰
    • 計劃支持 Component 構造器插件,在實例化一個自定義組件的時候,允許你在構造器的這個階段,加入一些邏輯,方便進行一些擴展,甚至是可以擴展成 Vue 的語法

    npm支持

    目前小程序開發的痛點是:開源組件要手動復制到項目,后續更新組件也需要手動操作。不久的將來,小程序將支持npm包管理,有了這

    相關標簽
    免費獲取專屬 《策劃方案 》及報價
    免費體驗我們的業務系統、OA系統、在線教育、電商系統、智慧辦公等產品定制化方案,助力您的信息化發展之路
    即時交流
    在線咨詢 電話咨詢
    在線咨詢
    產品經理

    一對一產品經理

    180 8812 7777
    電話咨詢

    電話咨詢

    0871-6718 6978
    到訪面聊
    返回頂部
    日本XXXX裸体XXXX在线观看,乱中年女人伦AV一区二区,色狠狠一区二区三区熟女