미니 프로그램 실행 과정 분석

王林
풀어 주다: 2021-02-03 10:39:32
앞으로
3113명이 탐색했습니다.

미니 프로그램 실행 과정 분석

소개:

WeChat Mini Program은 미니 프로그램의 일종으로 영어 이름은 Wechat Mini Program으로, 다운로드 및 설치 없이 사용할 수 있는 애플리케이션입니다. . 스캔하거나 검색하여 앱을 엽니다.

신청이 완전히 오픈된 후, 기업, 정부, 미디어, 기타 조직 또는 개인 개발자는 미니 프로그램 등록을 신청할 수 있습니다. WeChat 미니 프로그램, WeChat 구독 계정, WeChat 서비스 계정 및 WeChat 기업 계정은 병렬 시스템입니다.

최근 기본적인 서비스를 해왔는데, 모두 기술적인 시스템을 개선하기 위한 것이었고, 프론트엔드에서는 Hybrid 시스템을 구축해야 하는데, 앱을 만든다면 React Native도 좋은 선택입니다. 완벽한 레이어링이어야 함:

① 기본 프레임워크는 개발 효율성 문제를 해결하여 복잡한 부분을 블랙박스로 바꾸고 고정 모드에서 개발할 수 있는 페이지 개발을 위한 세 가지 고정 도구만 표시합니다.

② 엔지니어링 부서는 비즈니스 개발자입니다. 최소한의 개발 환경을 캡슐화하면 브라우저가 최고입니다. 불가능하다면 브라우저와 같은 디버깅 환경을 제공하세요

이렇게 하면 비즈니스 개발자가 작성한 코드가 유사하므로 기본 프레임워크가 협력합니다. 엔지니어링 팀(일반적으로 동일한 팀)은 최하위 수준에서 많은 효율성 및 성능 문제를 해결할 수 있습니다.

조금 더 큰 회사와 조금 더 관대한 팀에서는 후속 성능 모니터링과 오류 로깅 작업을 동시에 많이 수행하여 일련의 문서 ->개발->디버깅->빌드->릴리스-를 구성합니다. > ;모니터링과 분석은 완전한 기술 시스템입니다

이러한 시스템이 형성되면 후속 내부 프레임워크 변경 및 기술 혁신도 이 시스템에서 변환되지만 안타깝게도 많은 팀은 이 경로만 따르게 됩니다. 먼저, 여러 가지 이유로 더 이상 들어가지 마십시오. 가장 무서운 행동은 자신의 시스템이 형성되기 전에 성급하게 기본 프레임을 변경하는 것입니다.

제3자 애플리케이션 액세스 측면에서 보면 Baidu가 직접 계정 및 기타 유사한 제품을 보유하고 있지만 Alibaba도 유사한 기술 제품을 보유해야 한다는 점에서 여전히 개선이 필요합니다. 잘 모르니까 잘 운영이 안 되고 있거나, 잘 안 되고 있는 것 같아요.

미니 프로그램이 탄생할 때부터 주목해 왔습니다. 지금까지 전체 미니 프로그램 시스템은 매우 완벽합니다. Tencent 미니 프로그램과 Tencent Cloud는 내부 베타 개발자 도구를 사용하면 매우 완벽하게 통합됩니다. 모두 무료이고 순수 js입니다. 서버, 스토리지, CDN, 서비스 코드가 필요 없이 미니 프로그램의 프런트엔드와 백엔드만 얻으면 됩니다. 백엔드를 개발한 후에는 모두 무료입니다. 스스로 운영하고 유지하는 빅 킬러의 리듬. 가끔은 텐센트의 기술력이 정말 대단하다는 생각이 듭니다.

미니 프로그램의 구조 추적 가능성

미니 프로그램의 개발 문서는 아직 비교적 완성되어 있습니다. 아직 계정 신청->데모 과정에 익숙해지면 코드 목록을 살펴볼 수 있습니다. 프런트 엔드 코드는 도구를 사용하여 구축된 후 업로드되며, 백그라운드 서비스는 자체적으로 유지 관리되고 주소 매핑을 구성하며 여기서는 모두 테스트 계정을 사용할 수 있습니다.

1 appid wx0c387cc8c19bdf78
2 appsecret acd6c02e2fdca183416df1269d2e3fb9
로그인 후 복사

1년 이상의 개발 끝에 미니 프로그램으로 구성된 문서는 비교적 완성되었습니다. 문서와 데모를 통해 미니 프로그램에 대한 대략적인 판단을 내릴 수 있습니다.

미니 프로그램 실행 과정 분석

다음은 미니 프로그램입니다. 이 코드와 작업을 통해 기본적으로 미니 프로그램의 개요를 추측할 수 있습니다. 먼저 글로벌 컨트롤러 앱을 살펴보겠습니다.

//app.js
App({
  onLaunch: function () {
    // 展示本地存储能力
    var logs = wx.getStorageSync('logs') || []
    logs.unshift(Date.now())
    wx.setStorageSync('logs', logs)

    // 登录
    wx.login({
      success: res => {
        // 发送 res.code 到后台换取 openId, sessionKey, unionId
      }
    })
    // 获取用户信息
    wx.getSetting({
      success: res => {
        if (res.authSetting['scope.userInfo']) {
          // 已经授权,可以直接调用 getUserInfo 获取头像昵称,不会弹框
          wx.getUserInfo({
            success: res => {
              // 可以将 res 发送给后台解码出 unionId
              this.globalData.userInfo = res.userInfo

              // 由于 getUserInfo 是网络请求,可能会在 Page.onLoad 之后才返回
              // 所以此处加入 callback 以防止这种情况
              if (this.userInfoReadyCallback) {
                this.userInfoReadyCallback(res)
              }
            }
          })
        }
      }
    })
  },
  globalData: {
    userInfo: null
  }
})
로그인 후 복사

애플리케이션에는 APP 인스턴스가 하나만 있으며 미니 프로그램은 다음과 같습니다. 이 예제는 우리가 가장 많이 사용하는 몇 가지 기본 이벤트 정의를 제공합니다. onLaunch, onShow 및 onHide(아직 미니 프로그램을 작성하지 않았으므로 추측합니다):

미니 프로그램 실행 과정 분석

미니 프로그램 아키텍처 레이어는 여기 로직, APP에서 뷰를 인스턴스화하는 방법, 먼저 명확히 해야 할 몇 가지 사항이 있습니다.

1 실제로 WeChat 애플릿은 여전히 ​​웹뷰 실행 환경을 제공하므로 창, 위치 등에 계속 액세스할 수 있습니다. js 환경 속성

② WeChat 애플릿에서 제공하는 모든 디스플레이는 기본 맞춤형 UI이므로 DOM 작업에 대해 생각하지 마세요

여기서 애플릿 인터페이스에 실제 코드 로직을 실행하는 웹뷰가 있다고 상상할 수 있습니다. 그러나 이 웹뷰는 js 프로그램을 로드하는 것 외에는 아무것도 하지 않으며 모든 페이지 렌더링은 URL Schema 또는 JSCore를 통한 js의 Native 통신이며 이를 Native라고 하여 설정된 규칙에 따라 페이지 렌더링을 완료합니다.

글로벌 컨트롤러 앱

这里我们重点关注全局控制器App这个类做了什么,因为拿不到源码,我们这里也只能猜测加单步调试了,首先微信容器会准备一个webview容器为我们的js代码提供宿主环境,容器与构建工具会配合产出以下页面:

미니 프로그램 실행 과정 분석

他在这里应该执行了实例化App的方法:

미니 프로그램 실행 과정 분석

这一坨代码,在这个环境下便相当晦涩了:

y = function() {
            function e(t) {
                var n = this;
                o(this, e),
                s.forEach(function(e) {
                    var o = function() {
                        var n = (t[e] || i.noop).bind(this);
                        Reporter.__route__ = "App",
                        Reporter.__method__ = e,
                        (0,
                        i.info)("App: " + e + " have been invoked");
                        try {
                            n.apply(this, arguments)
                        } catch (t) {
                            Reporter.thirdErrorReport({
                                error: t,
                                extend: "at App lifeCycleMethod " + e + " function"
                            })
                        }
                    };
                    n[e] = o.bind(n)
                });
                for (var r in t)
                    !function(e) {
                        g(e) ? (0,
                        i.warn)("关键字保护", "App's " + e + " is write-protected") : v(e) || ("[object Function]" === Object.prototype.toString.call(t[e]) ? n[e] = function() {
                            var n;
                            Reporter.__route__ = "App",
                            Reporter.__method__ = e;
                            try {
                                n = t[e].apply(this, arguments)
                            } catch (t) {
                                Reporter.thirdErrorReport({
                                    error: t,
                                    extend: "at App " + e + " function"
                                })
                            }
                            return n
                        }
                        .bind(n) : n[e] = t[e])
                    }(r);
                this.onError && Reporter.registerErrorListener(this.onError);
                var l = function() {
                    "hang" === (arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}).mode && (f = !0);
                    var e = (0,
                    a.getCurrentPages)();
                    e.length && (e[e.length - 1].onHide(),
                    (0,
                    u.triggerAnalytics)("leavePage", e[e.length - 1], !0)),
                    this.onHide(),
                    (0,
                    u.triggerAnalytics)("background")
                }
                  , h = function() {
                    var e = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {};
                    if (0 === e.scene || "0" === e.scene ? e.scene = c : c = e.scene,
                    e.query = e.query || {},
                    (0,
                    i.hasExitCondition)(e) && (p = !0),
                    this.onShow(e),
                    (0,
                    u.triggerAnalytics)("foreground"),
                    d || e.reLaunch)
                        d = !1;
                    else {
                        var t = (0,
                        a.getCurrentPages)();
                        t.length && (t[t.length - 1].onShow(),
                        (0,
                        u.triggerAnalytics)("enterPage", t[t.length - 1], !0))
                    }
                };
                if ("undefined" != typeof __wxConfig && __wxConfig) {
                    var y = __wxConfig.appLaunchInfo || {};
                    y.query = y.query || {},
                    c = y.scene,
                    (0,
                    i.hasExitCondition)(y) && (p = !0),
                    this.onLaunch(y),
                    (0,
                    u.triggerAnalytics)("launch"),
                    h.call(this, y)
                } else
                    (0,
                    i.error)("App Launch Error", "Can not find __wxConfig");
                wx.onAppEnterBackground(l.bind(this)),
                wx.onAppEnterForeground(h.bind(this)),
                _.call(this, "function" == typeof t.onPageNotFound)
            }
            return r(e, [{
                key: "getCurrentPage",
                value: function() {
                    (0,
                    i.warn)("将被废弃", "App.getCurrentPage is deprecated, please use getCurrentPages.");
                    var e = (0,
                    a.getCurrentPage)();
                    if (e)
                        return e.page
                }
            }]),
            e
        }();
로그인 후 복사

미니 프로그램 실행 과정 분석

这里会往App中注册一个事件,我们这里注册的是onLaunch事件,这里对应的是当小程序初始化时候会执行这个回调,所以原则上应该是Native装在成功后会执行这个函数,这里再详细点说明下H5与Native的交互流程(这里是我之前做Hybrid框架时候跟Native同事的交互约定,小程序应该大同小异):

我们一般是在全局上会有一个对象,保存所有需要Native执行函数的对象,比如这里的onLaunch,Native在执行到一个状态时候会调用js全局环境该对象上的一个函数
因为我们js注册native执行是以字符串key作为标志,所以Native执行的时候可能是window.app['onLauch...']('参数')
而我们在window对象上会使用bind的方式将对应的作用域环境保留下来,这个时候执行的逻辑便是正确的

这里在小程序全局没有找到对应的标识,这里猜测是直接在app对象上,Native会直接执行APP对象上面的方法,但是我这里有个疑问是View级别如果想注册个全局事件该怎么做,这个留到后面来看看吧,这里是Native载入webview时,会执行对象定义的onLaunch事件,在下面的代码看得到:

미니 프로그램 실행 과정 분석

这里会结合app.json获取首先加载页面的信息,默认取pages数组第一个,但是具体哪里获取和设置的代码没有找到,也跟主流程无关,我们这里忽略......然后我们看到代码执行了onShow逻辑:

미니 프로그램 실행 과정 분석

然后流转到注册微信容器层面的事件,我觉得,无论如何,这里应该是像微信容器注册事件了吧,但是我找不到全局的key

미니 프로그램 실행 과정 분석

Page流程

如果有微信小程序的同学,麻烦这里指点一下,是不是猜测正确,顺便可以帮忙说明下这里,这里也是我觉得全局key,被Native调用的点,然后,逻辑上会获取默认view的类开始做实例化,我们这里来到view级别代码:

//index.js
//获取应用实例
const app = getApp()

Page({
  data: {
    motto: 'Hello Wor11ld',
    userInfo: {},
    hasUserInfo: false,
    canIUse: wx.canIUse('button.open-type.getUserInfo')
  },
  //事件处理函数
  bindViewTap: function() {
    wx.navigateTo({
      url: '../logs/logs'
    })
  },
  onLoad: function () {
    if (app.globalData.userInfo) {
      this.setData({
        userInfo: app.globalData.userInfo,
        hasUserInfo: true
      })
    } else if (this.data.canIUse){
      // 由于 getUserInfo 是网络请求,可能会在 Page.onLoad 之后才返回
      // 所以此处加入 callback 以防止这种情况
      app.userInfoReadyCallback = res => {
        this.setData({
          userInfo: res.userInfo,
          hasUserInfo: true
        })
      }
    } else {
      // 在没有 open-type=getUserInfo 版本的兼容处理
      wx.getUserInfo({
        success: res => {
          app.globalData.userInfo = res.userInfo
          this.setData({
            userInfo: res.userInfo,
            hasUserInfo: true
          })
        }
      })
    }
  },
  getUserInfo: function(e) {
    console.log(e)
    app.globalData.userInfo = e.detail.userInfo
    this.setData({
      userInfo: e.detail.userInfo,
      hasUserInfo: true
    })
  }
})
로그인 후 복사

他首先一来便获取了当前app实例:

const app = getApp()

其次开始了view实例化流程,这个是Page的类入口,大家要注意view.js只是定义的类,但是其实例化应该在全局的控制器,其实例化在这里完成的:

미니 프로그램 실행 과정 분석

总结

我们这里一起瞎子摸象一般对微信小程序架构做了简单的摸索,这里发现事实上小程序流程与自己所想有一些出入,这里初步认为流程是这样的:

① 我们写好小程序代码后,提交代码

② 在发布流程中我们的代码经过构建流程,app.json以及入口的index.html(伪造页面),重新组装为一个只有js代码的空页面

③ 这里开始载入流程,用户点击一个微信按钮,进入小程序

④ 微信容器开启Hybrid容器,webview载入入口页面(我感觉应该有个规则可以通过url去打开固定一个小程序页面,这里后续碰到开发案例再说)

⑤ webview执行环境实例化App,其后自动装载默认Page(这里默认是index)

PS:这里我有个很疑惑的点,微信Native容器的各个事件点什么时候执行,由谁执行?

⑥ 进入页面渲染逻辑

⑦ ......

这里我还比较在意,执行事件后,对应Native页面是如何进行更新的,所以我们这里关注下这段代码:

1 debugger;
2 this.setData({
3   userInfo: app.globalData.userInfo,
4   hasUserInfo: true
5 })
로그인 후 복사

미니 프로그램 실행 과정 분석

这里出现了一段非常关键的代码:

미니 프로그램 실행 과정 분석

미니 프로그램 실행 과정 분석

可以看到,我们这里往微信容器注册了一个appDataChange的异步事件,而这个时候就将所有的逻辑交给了Native本身,Native执行结束后会根据webviewIds找到后续要执行的回调继续执行。

미니 프로그램 실행 과정 분석

至于,容器如何使用webviewId找到对应函数的代码,我没有找到。至此,我们对小程序结构的初步探索便结束了,我们本周后面时间继续来对小程序进行深入学习。

相关推荐:小程序开发教程

위 내용은 미니 프로그램 실행 과정 분석의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

관련 라벨:
원천:cnblogs.com
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
최신 이슈
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿