Advanced cross-platform application development (fifty-six): Analysis and resolution of abnormal application rendering problems

I. Introduction

Following the previous iOS page white screen problem due to insufficient mobile device memory, (see the blog post "Advanced Cross-platform Application Development (50) uni-app ios web-view nested H5 project white screen problem analysis and solution ") It is found that during the running of the system, the APP iOSwill frequently appear black screens, black blocks, and white screens.

insert image description here
insert image description here

2. Problem Analysis

The above problems are caused by page rendering problems, which may be caused by page stack overflow and application memory leaks.

After getCurrentPages()outputting the page stack information, it is found that when the bottom navigation is switched, the page stack information has been cleared, so there is no page stack overflow problem.

Continue to try the APP cache cleaning mechanism, and formulate the cleaning strategy as follows:

Click the current tabitem, scroll or refresh the current page to call the native method plus.cache.clearto clear the application cache. If you click on a different tabitem, it will definitely trigger a page switch.

// 点击 tab 时触发
onTabItemTap (e) {
    
    
	// #ifdef APP-PLUS
	plus.cache.clear( function () {
    
    
		console.log( "Clear application cache successful!" );
	});
	// #endif
},

After the implementation of the clean cache policy, the problem was solved.

From this, is it derived to call uni.setStorage(OBJECT)(macrotask), uni.setStorageSync(KEY,DATA)(microtask) and other APIs uni.downloadFile, and uni.saveFileis it stored in the device memory?

3. Extended reading

3.1 Page Jump

  • uni.navigateTo(OBJECT)
    The page stack is preserved and can be navigateBackreturned by calling. However, there is a problem of page stack overflow, so it cannot be used as a general jump method.

  • uni.redirectTo(OBJECT)
    The page stack will not be preserved, the previous page cannot be returned, and the default pages.jsonfirst page will be returned.

  • uni.reLaunch(OBJECT)
    Destroy the page stack and jump to the specified page. Usually used to log out and return to the home page.

  • uni.switchTab(OBJECT)
    Used to switch tabs.

  • uni.navigateBack(OBJECT)
    Cooperate navigateToand return to the page to use, which can effectively avoid page stack overflow. You can getCurrentPages()get the current page stack and decide how many layers you need to return.

Through the analysis of the project code, it is found that there is no page stack overflow exception in the routing jump. When the bottom navigation bar is switched, the page stack will be cleared. Only page jumps under the same navigation bar will be in the page stack.

2 Troubleshooting ideas

  1. According to the specific business scenario, logically control the page jump and return to prevent the page stack from overflowing. By getCurrentPages()judging how high the page stack is and checking webviewthe number of objects, we can judge whether the current jump method is appropriate.
  2. Check the code logic, if there is a problem that the background request does not return for a long time, you can uni.requestadd it timeoutto avoid this situation.
  3. Check for memory overflow, whether there is a timer created ( setInterval), but not cleared ( clearInterval).
  4. uniappThe problem itself, because its cross-platform needs to jsbe called native, the performance will definitely be lost. If it is unacceptable, it should be developed in native language.
  5. When deleting the cache, it needs to be used if the data is cleared uni.clearStorageSync.

Then you need to check the memory occupied by the application during running to see if there is a memory leak.

3.2 In-depth analysis of $nextTick principle

VueRealizing responsiveness does not mean DOMchanging immediately after the data changes, but updating according to a certain strategy DOM. $nextTickThe delayed callback is executed after the end of the next DOMupdate cycle. After modifying the data $nextTick, the updated data can be obtained in the callback DOM, and the delayed callback is executed after the end of the next DOMupdate cycle.

The simple understanding is: when the data is updated and domrendered in , the function is automatically executed. The above data will not be updated immediately after Vuethe update , that is to say, if we modify the data in and immediately obtain the above value, what we get is the old value, and we put the operation of obtaining the above value into it, and we can get The updated data.dataDOMdataDOMDOM$nextTick

insert image description here
insert image description here
insert image description here

The correct usage is: after vue changes the data in data, use the vue.$nextTick()method to wrap the js object to execute the subsequent code.

insert image description here
insert image description here

3.2.1 When to use $nextTick()

Vuecreated()The DOM operation performed by the hook function of the life cycle must be placed Vue.nextTick()in the callback function. The reason is that created()when the hook function is executed, the DOM does not actually perform any rendering, and it is useless to perform DOM operations at this time. Different from futile, so here must put the js code of DOM operation into Vue.nextTick()the callback function.

When the data of the function is changed in the project dataand you want to do something based on the new dom, DOMyou need to put the new series of js operations Vue.nextTick()into the callback function.

3.2.2 $nextTick() execution principle

VueDOMUpdates are performed asynchronously. As long as data changes are detected, Vuea task queue will be opened and all data changes that occur in the same time loop will be buffered. If the same watcheris triggered multiple times, it will only be pushed into the queue once. (This deduplication during buffering is very important to avoid unnecessary calculations and DOMoperations )

Then, in the next event loop " tick", Vuethe queue is flushed and the task queue (deduplicated) work is executed.

VueInternally try to use native Promise.then(microtasks) for asynchronous queues, MutationObserverand setImmediateif the execution environment does not support it, it will use setTimeout(fn, 0)(macrotasks) instead.

3.3 JS operating mechanism

JSExecution is single-threaded and it's event loop based. The event loop is roughly divided into the following steps:

  1. All synchronization tasks are executed on the main thread, forming an execution stack ;
  2. In addition to the main thread, there is also a " task queue " ( task queue).
  3. As long as the asynchronous task has a running result, an event is placed in the " task queue ".
  4. Once all the synchronous tasks in the " execution stack " have been executed, the system will read the " task queue " to see what events are in it. Those corresponding asynchronous tasks end the waiting state, enter the execution stack, and start executing. The main thread keeps repeating the third step above.

insert image description here

The execution process of the main thread is a tick, and all asynchronous results are scheduled through the " task queue ". The " task queue " stores tasks one by one. The specification stipulates that tasks are divided into two categories, macro tasks and micro tasks .

insert image description here

3.3.1 Microtasks

Also known as job, it is usually used for things that happen directly after the currently executing script, such as reacting to a series of behaviors, or doing some asynchronous tasks without creating a new task. javascriptAt the end of each task, the microtask queue is processed after the callback, as long as nothing else is executing in the execution stack . Other microtasks queued during the microtask will be added to the end of this queue.

Common microtasks are MutationObsever, Promise.then, $nextTiock.

3.3.2 Macro task

The role of the macro task is to allow the browser to obtain javascript / domthe content from the inside and ensure that the execution stack can proceed sequentially. Scheduling is everywhere, such as parsing HTML, getting mouse click event callbacks, and so on.

The common macro tasks are setTimeout, MessageChannel, postMessage, setImmediate;

vueFor DOM update, it is also called internally nextTickfor asynchronous queue control. And when we call it ourselves nextTick, it adds our own callback function after the micro task that updates the DOM, so as to ensure that our code is executed after the DOM is updated.

setTimeoutIt is a macro task: it is only delayed execution. In the delayed execution method, DOMit may or may not be updated.

3. Solutions

Note ⚠️:

  • uni-appThe built-in HTML5+engine allows js to directly call rich native capabilities.

    Conditional compilation call HTML5+: There is no HTML5+extension , so when callinguni-app the extension specification of , you need to pay attention to the use of conditional compilation. HTML5+Otherwise, plus is not definederrors .

    // #ifdef APP-PLUS
    var appid = plus.runtime.appid;
    console.log('应用的 appid 为:' + appid);
    // #endif
    
  • uni-appThe logic layer runs in an independent environment jscore, which does not depend on the local machine webview, so on the one hand, it has no browser compatibility issues and can Android4.4run es6code on it; on the other hand, it cannot run window、document、navigator、localstorageother browser-specific js APIs.

    jscoreIt is a standard js engine, and standard js can run normally, such as if, for, various strings, date processing, etc. The difference between js and browser should be distinguished.

  • uni-appThere is no such thing as an App on the App side webkit remote debug, because uni-appthe js does not run in webviewit, but is independent jscore.

  • Since the browser GUI rendering thread and the JS engine thread are mutually exclusive, when the JS engine executes, the GUI thread will be suspended until the execution of the JS engine ends. When there are many long tasks on the page, it will cause the page UI to be blocked, and the interface will be stuck and frames will be dropped.

GUI rendering threadhtml、css : responsible for page drawing and rendering, resource parsing, dom tree generation, and page drawing that we are familiar with are all responsible for this thread.
JS engine thread : Responsible for js parsing and execution of all asynchronous and synchronous tasks, maintaining an execution stack, first processing synchronous codes one by one, when encountering asynchronous tasks, it will use events to trigger threads.

The process and thread information of the browser is as follows:
insert image description here
Among them, the front-end mainly focuses on the rendering process of the browser kernel, which is mainly responsible for html、css、jsresource parsing and rendering, and is also responsible for event loops and asynchronous requests.

Data storage: Are the cache and H5 cache in uni-app stored in memory?

  • The native plus Storagemodule manages the application's local data storage area, which is used for saving and reading application data. The difference between application local data and and localStorageis that the data is valid in different domains . The former can be operated across domains within the application. The data storage period is persistent and there is no capacity limit. Through can get application local data management object.sessionStorageplus.storage

  • uni-appWhen applications uni.setStorage(OBJECT)(macrotasks) and uni.setStorageSync(KEY,DATA)(microtasks) store data, the essence is to use native plus.storage, no size limit, not cache, but to store data in sqlitedatabase files for persistence.

  • The App also supports local storage solutions such as SQLite and IO files .

  • For H5 applications localStorageand sessionStoragedata storage, the browser limits the size to 5M, which is a cache concept and may be cleaned up.

  • The application Vueximplements state management.

  • Native plus.cachemanagement application cache data includes only webviewthe data generated in the program, and does not include the data saved in the business logic using extensions api(such as uni.setStorage(OBJECT)(macrotask), uni.setStorageSync(KEY,DATA)(microtask) and other APIs).

  • Each applet comes with its own storage api, and the data storage life cycle is consistent with the applet itself, that is, unless the user actively deletes or is automatically cleaned up after a certain period of time, the data is always available.

  • uni-appFor problems that cannot be solved by the framework components themselves, the framework components can be discarded and optimized using native components.

In the end, choose to do cache cleaning when switching the bottom tab. Note that the cache cleaning here is used plus.cache.clearto clear the cache data of the application. Clearing application cache data only includes webviewdata generated by use in the program, and does not include apidata saved by extensions in business logic. code show as below:

// 点击 tab 时触发
onTabItemTap (e) {
    
    
	console.log('-----------点击 tab 时触发-----------', e);
	// #ifdef APP-PLUS
	plus.cache.clear( function () {
    
    
		console.log( "component Clear application cache successful!" );
	});
	// #endif
},

4. Extended reading

Guess you like

Origin blog.csdn.net/sunhuaqiang1/article/details/129224778