Wechat applets app. OnLaunch and Page. OnLoad asynchrony problem

Question:

I believe many people have encountered this problem, usually we will launch app.onlaunch () to initiate silent login, and we need to call a backend API that requires login state when loading the page. Since both are asynchronous, it is common for page.onload() to call the API before the static login process called in app.onlaunch () has completed, causing the request to fail.

Solution:

1. Through the callback function

// on app.js
App({
    onLaunch() {
      login()
      	// Set hasLogin to true
        .then(() = > {
        	this.globalData.hasLogin = true;
          if (this.checkLoginReadyCallback) {
            this.checkLoginReadyCallback(); }})// Set hasLogin to false
        .catch(() = > {
        	this.globalData.hasLogin = false; }); }});// on page.js
Page({
    onLoad() {
      if (getApp().globalData.hasLogin) { // Login completed
            fn() // do something
      } else {
            getApp().checkLoginReadyCallback = () = > {
              fn()
            }
      }
    },
});

Copy the code

⚠️ Note: This method has some drawbacks (if there are multiple components in the startup page that need to determine the login situation, multiple asynchronous callbacks will be generated, and the process is redundant) and is not recommended.


2. Use Object.defineProperty to listen for the hasLogin value in globalData

// on app.js
App({
    onLaunch() {
      login()
      	// Set hasLogin to true
        .then(() = > {
        	this.globalData.hasLogin = true;
      	})
      	// Set hasLogin to false
        .catch(() = > {
        	this.globalData.hasLogin = false;
      	});
    },
  	// Listen for the hasLogin attribute
    watch: function (fn) {
        var obj = this.globalData
        Object.defineProperty(obj, 'hasLogin', {
          configurable: true.enumerable: true.set: function (value) {
            this._hasLogin = value;
            fn(value);
          },
          get: function () {
            return this._hasLogin
          }
        })
    },
});

// on page.js
Page({
    onLoad() {
      if (getApp().globalData.hasLogin) { // Login completed
            fn() // do something
      } else {
            getApp().watch(() = > fn())
      }
    },
});
Copy the code

Through 3.beautyweState machine plug-in (used in the project)

// on app.js
import { BtApp } from '@beautywe/core/index.js';
import status from '@beautywe/plugin-status/index.js';
import event from '@beautywe/plugin-event/index.js';

const app = new BtApp({
    onLaunch() {
      // Initiate a silent login call
      login()

      // Set the state machine to SUCCESS
        .then(() = > this.status.get('login').success())

      // Set the state machine to fail
        .catch(() = > this.status.get('login').fail()); }});// The status plugin depends on beautywe-plugin-event
app.use(event());
 
// Use the status plugin
app.use(status({
  statuses: [
    'login']}));// Use the native App method
App(app);


// on page.js
Page({
    onLoad() {
      // Must is used to determine the state, such as waiting for the login, returning if the login succeeds, or throwing if the login fails.
      getApp().status.get('login').must().then(() = > {
        // Perform some operations that require login state...})}});Copy the code

The specific implementation

Specific implementation can refer to my mall small program project experience address: experience code: code