ホームページ  >  記事  >  WeChat アプレット  >  ミニプログラム実行プロセス解析

ミニプログラム実行プロセス解析

王林
王林転載
2021-02-03 10:31:113099ブラウズ

ミニプログラム実行プロセス解析

はじめに:

WeChat ミニ プログラムは、ミニ プログラムの一種で、英語名は Wechat Mini Program で、ダウンロードとインストールを必要としないアプリケーションです。は、アプリケーションを「すぐに使える」ようにするという夢を実現し、ユーザーはスキャンや検索によってアプリケーションを開くことができます。

アプリケーションが完全に公開されると、企業、政府、メディア、その他の組織または個人である開発者は、ミニ プログラムの登録を申請できます。 WeChat ミニ プログラム、WeChat サブスクリプション アカウント、WeChat サービス アカウント、および WeChat エンタープライズ アカウントは並列システムです。

最近は基本的なサービスを行っていますが、すべて技術体系の改善を目的としています。フロントエンドについてはハイブリッドシステムを構築する必要があります。アプリを構築する場合は、React Native も有効です。

① 基盤となるフレームワークは開発効率の問題を解決し、複雑な部分をブラックボックス化し、ページ開発に 3 つの固定ツールを表示するだけで開発可能です。固定モード

② エンジニアリング部門は、ビジネス開発者向けに最小限の開発環境をカプセル化します。ブラウザが最適です。それが不可能な場合は、ブラウザに似たデバッグ環境を提供します。

このようにして、ビジネスは迅速な反復を行うことができます。ビジネス開発者によって書かれたコードは類似しているため、基礎となるフレームワークとエンジニアリング チーム (通常は同じチーム) が、効率とパフォーマンスに関する多くの問題を最下位レベルで解決できます。

少し大きな会社ともう少し寛大なチームは、その後の多くのパフォーマンス監視とエラーログの作業も同時に実行し、一連のドキュメント -> 開発 -> デバッグ -> ビルド - を形成します。 > ;リリース->監視と分析は完全な技術体系です

このような体系が構築されれば、その後の社内体制の変更や技術革新もこの体系に基づいて行われることになりますが、残念ながら多くのチームはこの道筋の一部だけを実行するだけで、さまざまな理由でそれ以上深くは進めず、それを無駄に感じて、自分たちのシステムが形成される前に基本的な枠組みを軽率に変更することが最も恐ろしい行為であるため、注意してください。

サードパーティ アプリケーションへのアクセスという点では、WeChat が最適です。Baidu には直接アカウントやその他の同様の製品がありますが、体系的な雰囲気はまだ改善の必要があります。Alibaba にも同様の製品があるはずです。技術的な製品の場合私たちの観点から見ると、それらについてあまり知らないので、それらはうまく運営されていないか、不十分に行われています。

ミニ プログラムの誕生以来、私はミニ プログラムに注目してきました。これまでのところ、ミニ プログラム システム全体は非常に完成度が高いです。Tencent ミニ プログラムと Tencent Cloud は深く統合されています。開発者ツールを使用すると、内部テスト、すべて無料です。Pure JS は、ミニ プログラムのフロントエンドとバックエンドを処理できます。サーバー、ストレージ、CDN、またはサービス コードは必要ありません。すべて無料です。バックエンドの開発後は、自分で運用・保守する必要がない、大キラーのリズム、テンセントの技術力を時々思う、本当に強い!

ミニ プログラムの構造トレーサビリティ

ミニ プログラムの開発ドキュメントは比較的完成しています。まだアカウントの申請→デモのプロセスです。慣れれば、これを使用してコーディングを開始できます。棚に置くプロセスの準備が整います。フロントエンド コードはツールを使用して構築され、アップロードされます。バックエンド サービスはそれ自体で維持され、アドレス マッピングが設定されます。私たちだけです。ここでは開発プロセスに焦点を当てており、テスト アカウントを使用してすべてを行うことができます。

1 appid wx0c387cc8c19bdf78
2 appsecret acd6c02e2fdca183416df1269d2e3fb9

1 年以上の開発を経て、ミニ プログラムによって形成されたドキュメントは比較的完成しました。ドキュメントとデモからミニ プログラムについて大まかな判断を下すことができます:

ミニプログラム実行プロセス解析

ビジネス担当者が見ることができるミニ プログラムのコードは次のとおりです。このコードと動作から、ミニ プログラムの概要はほぼ推測できます。ここでは、まずそのグローバル コントローラー APP を見てください。 :

//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 インスタンスが 1 つだけあり、アプレットはこの 1 つのインスタンスに対していくつかの基本的なイベント定義を提供します。最も使用するのは、onLaunch、onShow、および onHide です (私は、アプレットはまだ存在しないので、推測します):

ミニプログラム実行プロセス解析

アプレット アーキテクチャ レイヤーの実行ロジックと、それを APP からビューにインスタンス化する方法をトレースしましょう。ここで最初に明確にします。いくつかのポイント:

① 実際、WeChat アプレットは引き続き Webview 実行環境を提供するため、JS 環境のウィンドウや位置などのプロパティに引き続きアクセスできます

② 提供されるすべてのディスプレイWeChat アプレットはネイティブにカスタマイズされた UI であるため、DOM 操作については考えません。

ミニ プログラム インターフェイスには、実際のコード ロジックを実行する Web ビューがあると想像できますが、この Web ビューはロード以外は何も行いません。 js プログラム. それを実行すると、すべてのページ レンダリングは URL スキーマまたは JSCore を介して js によって実行されるネイティブ通信であり、設定されたルールに従ってページ レンダリングを完了するためにネイティブと呼ばれます。

グローバル コントローラー アプリ

这里我们重点关注全局控制器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 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はcnblogs.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。