고급 크로스 플랫폼 애플리케이션 개발(56개): 비정상적인 애플리케이션 렌더링 문제 분석 및 해결

I. 소개

모바일 기기 메모리 부족으로 인한 이전 iOS 페이지 흰색 화면 문제에 이어(블로그 게시물 "Advanced Cross-platform Application Development (50) uni-app ios web-view nested H5 project white screen problem analysis and solution" 참조 ) 입니다. 시스템을 실행하는 동안 앱에 iOS검은색 화면, 검은색 블록 및 흰색 화면이 자주 나타납니다.

여기에 이미지 설명 삽입
여기에 이미지 설명 삽입

2. 문제 분석

위의 문제는 페이지 스택 오버플로 및 응용 프로그램 메모리 누수로 인해 발생할 수 있는 페이지 렌더링 문제로 인해 발생합니다.

페이지 스택 정보 출력 후 getCurrentPages()하단 내비게이션 전환 시 페이지 스택 정보가 지워져 페이지 스택 오버플로 문제가 없는 것으로 확인되었습니다.

계속해서 APP 캐시 정리 메커니즘을 시도하고 다음과 같이 정리 전략을 공식화합니다.

현재 탭 항목을 클릭하고 현재 페이지를 스크롤하거나 새로 고쳐 네이티브 메서드를 호출하여 plus.cache.clear애플리케이션 캐시를 지웁니다. 다른 탭 항목을 클릭하면 확실히 페이지 전환이 트리거됩니다.

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

클린 캐시 정책을 구현한 후 문제가 해결되었습니다.

uni.setStorage(OBJECT)이로부터 (macrotask), ( uni.setStorageSync(KEY,DATA)microtask) 및 기타 API를 호출하기 위해 파생되며 장치 메모리에 저장됩니까?uni.downloadFileuni.saveFile

3. 확장 독서

3.1 페이지 이동

  • uni.navigateTo(OBJECT)
    페이지 스택은 보존되며 navigateBack호출하여 반환할 수 있습니다. 그러나 페이지 스택 오버플로 문제가 있어 일반적인 점프 방식으로는 사용할 수 없다.

  • uni.redirectTo(OBJECT)
    페이지 스택은 보존되지 않고 이전 페이지는 반환할 수 없으며 기본 pages.json첫 번째 페이지가 반환됩니다.

  • uni.reLaunch(OBJECT)
    페이지 스택을 파괴하고 지정된 페이지로 이동합니다. 일반적으로 로그아웃하고 홈페이지로 돌아갈 때 사용합니다.

  • uni.switchTab(OBJECT)
    탭을 전환하는 데 사용됩니다.

  • uni.navigateBack(OBJECT)
    페이지 스택 오버플로를 효과적으로 피할 수 있는 협력 navigateTo하고 사용할 페이지로 돌아갑니다. getCurrentPages()현재 페이지 스택을 가져오고 반환해야 하는 레이어 수를 결정할 수 있습니다.

프로젝트 코드 분석을 통해 라우팅 점프에서 페이지 스택 오버플로우 예외가 없음을 발견했습니다. 하단 탐색 모음이 전환되면 페이지 스택이 지워집니다. 동일한 탐색 모음 아래의 페이지 점프만 페이지 스택에 있습니다.

2 문제 해결 아이디어

  1. 특정 비즈니스 시나리오에 따라 페이지 점프 및 반환을 논리적으로 제어하여 페이지 스택이 오버플로되지 않도록 합니다. getCurrentPages()페이지 스택이 얼마나 높은지 판단하고 개체 수를 확인하여 현재 webview점프 방법이 적절한지 판단할 수 있습니다.
  2. 코드 논리를 확인하고 백그라운드 요청이 오랫동안 반환되지 않는 문제가 있는 경우 uni.request이를 추가하여 timeout이러한 상황을 방지할 수 있습니다.
  3. 타이머가 생성되었지만( setInterval) 지워지지 않았는지( clearInterval) 메모리 오버플로를 확인합니다.
  4. uniapp문제 자체는 크로스플랫폼을 js호출해야 하기 때문에 native당연히 성능이 떨어지게 되는데, 받아들일 수 없다면 자국어로 개발해야 한다.
  5. 캐시를 삭제할 때 데이터가 지워지면 사용해야 합니다 uni.clearStorageSync.

그런 다음 실행 중에 응용 프로그램이 차지하는 메모리를 확인하여 메모리 누수가 있는지 확인해야 합니다.

3.2 $nextTick 원칙에 대한 심층 분석

Vue응답성을 확보하는 것은 데이터가 변경된 직후에 변경하는 것이 DOM아니라 특정 전략에 따라 업데이트하는 것입니다 DOM. $nextTick다음 DOM업데이트 , 데이터를 수정한 후 사용하고 $nextTick, 콜백에서 업데이트된 것을 얻을 수 있으며 DOM, 다음 DOM업데이트 .

간단한 이해는 데이터가 dom에서 업데이트되고 렌더링될 때 기능이 자동으로 실행된다는 것입니다. Vue위의 데이터는 업데이트 data직후에 업데이트되지 않습니다 DOM. 즉, data데이터를 수정하고 즉시 DOM위 값을 얻으면 이전 값을 얻고 DOM위 값을 얻는 작업을 $nextTick여기에 넣습니다 , 업데이트된 데이터를 얻을 수 있습니다.

여기에 이미지 설명 삽입
여기에 이미지 설명 삽입
여기에 이미지 설명 삽입

올바른 사용법은 다음과 같습니다. vue가 데이터의 데이터를 변경한 후 vue.$nextTick()메서드를 사용하여 js 개체를 래핑하여 후속 코드를 실행합니다.

여기에 이미지 설명 삽입
여기에 이미지 설명 삽입

3.2.1 $nextTick() 사용 시기

Vue라이프 사이클의 created()훅 함수가 수행하는 DOM 연산은 Vue.nextTick()콜백 함수에 넣어야 하는데, 그 이유는 created()훅 함수가 실행될 때 DOM은 실제로 렌더링을 수행하지 않으며 이때 DOM 연산을 수행하는 것은 쓸모가 없기 때문입니다. 쓸데없는 것과 다르므로 여기에 DOM 작업의 js 코드를 Vue.nextTick()콜백 함수에 넣어야 합니다.

프로젝트에서 함수의 데이터가 변경되고 data새로운 dom을 기반으로 무언가를 하고 싶을 때, 새로운 일련의 js 작업을 콜백 함수에 DOM넣어야 합니다 .Vue.nextTick()

3.2.2 $nextTick() 실행 원칙

VueDOM업데이트는 비동기식으로 수행됩니다. 데이터 변경이 감지되는 한 Vue작업 대기열이 열리고 동일한 시간 루프에서 발생하는 모든 데이터 변경이 버퍼링됩니다. 동일한 watcher항목이 대기열에 한 번만 푸시됩니다. (버퍼링 중 중복 제거는 불필요한 계산 및 DOM작업을 )

그런 다음 다음 이벤트 루프 " tick" 에서 Vue큐가 플러시되고 태스크 큐(중복 제거) 작업이 실행됩니다.

VuePromise.then내부적으로는 비동기 큐에 대해 네이티브(마이크로태스크)를 사용하려고 MutationObserver하고 , 실행 환경에서 지원하지 않는 경우 대신 (매크로태스크)를 setImmediate사용합니다 .setTimeout(fn, 0)

3.3 JS 작동 메커니즘

JS실행은 단일 스레드이며 이벤트 루프 기반입니다. 이벤트 루프는 대략 다음 단계로 나뉩니다.

  1. 모든 동기화 작업은 기본 스레드에서 실행되어 실행 스택을 형성합니다 .
  2. 메인 스레드 외에도 " 태스크 큐 "( task queue)도 있습니다.
  3. 비동기 작업에 실행 결과가 있는 한 이벤트는 " 작업 대기열 " 에 배치됩니다 .
  4. " 실행 스택 " 의 모든 동기 작업이 실행되면 시스템은 " 작업 대기열 "을 읽고 그 안에 어떤 이벤트가 있는지 확인합니다. 해당 비동기 작업은 대기 상태를 종료하고 실행 스택에 들어가 실행을 시작합니다. 메인 스레드는 위의 세 번째 단계를 계속 반복합니다.

여기에 이미지 설명 삽입

메인 스레드의 실행 프로세스는 틱이며 모든 비동기 결과는 " 태스크 큐 "를 통해 예약됩니다. " 작업 대기열 "은 작업을 하나씩 저장합니다. 사양에서는 작업을 매크로 작업마이크로 작업의 두 가지 범주로 구분한다고 규정합니다 .

여기에 이미지 설명 삽입

3.3.1 마이크로태스크

라고도 하며 일반적으로 job일련의 동작에 반응하거나 새 작업을 만들지 않고 일부 비동기 작업을 수행하는 것과 같이 현재 실행 중인 스크립트 직후에 발생하는 작업에 사용됩니다. 실행 스택에서 아무 것도 실행하지 않는 한 javascript각 작업이 끝날 때 콜백 후 마이크로 작업 대기열이 처리됩니다 . 마이크로태스크 중에 대기열에 있는 다른 마이크로태스크는 이 대기열의 끝에 추가됩니다.

일반적인 마이크로태스크는 MutationObsever, Promise.then, 입니다 $nextTiock.

3.3.2 매크로 작업

매크로 작업의 역할은 브라우저가 javascript / dom내부에서 콘텐츠를 가져오고 실행 스택이 순차적으로 진행될 수 있도록 하는 것입니다. 스케줄링은 HTML 구문 분석, 마우스 클릭 이벤트 콜백 가져오기 등 어디에나 있습니다.

일반적인 매크로 작업은 setTimeout, MessageChannel, postMessage, setImmediate;

vueDOM 업데이트의 경우 비동기 대기열 제어를 위해 내부적으로 호출되기도 합니다 nextTick. 그리고 우리가 직접 호출하면 nextTickDOM을 업데이트하는 마이크로 작업 뒤에 자체 콜백 함수를 추가하여 DOM이 업데이트된 후 코드가 실행되도록 합니다.

setTimeout매크로 작업: 지연된 실행일 뿐이며 지연된 실행 방법에서는 DOM업데이트되거나 업데이트되지 않을 수 있습니다.

3. 솔루션

참고 ⚠️:

  • uni-app앱 측의 내장 HTML5+엔진을 js는 풍부한 기본 기능을 직접 호출할 수 있습니다.

    조건부 컴파일 호출 HTML5+: 애플릿, H5 등의 플랫폼에 대한 HTML5+확장 의 확장 사양을 호출할uni-app 때 조건부 컴파일 사용에 주의가 필요합니다. HTML5+그렇지 않으면 h5 및 애플릿과 같은 플랫폼에서 실행할 때 plus is not defined오류가 .

    // #ifdef APP-PLUS
    var appid = plus.runtime.appid;
    console.log('应用的 appid 为:' + appid);
    // #endif
    
  • uni-app논리 계층은 jscore로컬 시스템에 의존하지 않는 독립적인 환경에서 실행되므로 webview한편으로는 브라우저 호환성 문제가 없고 코드를 Android4.4실행할 수 있습니다 es6. 다른 한편으로는 window、document、navigator、localstorage다른 브라우저별 js를 실행할 수 없습니다. 아피스.

    jscore표준 js 엔진이며 if, for, 각종 문자열, 날짜 처리 등 표준 js가 정상적으로 실행될 수 있습니다. js와 브라우저의 차이점은 구별되어야 합니다.

  • uni-app앱 측에 앱과 같은 것은 없습니다 webkit remote debug. uni-appjs가 실행되지 않고 webview독립적이기 때문입니다 jscore.

  • 브라우저 GUI 렌더링 스레드JS 엔진 스레드는 상호 배타적이므로 JS 엔진이 실행될 때 GUI 스레드는 JS 엔진 실행이 종료될 때까지 일시 중지됩니다. 페이지에 긴 작업이 많으면 페이지 UI가 차단되고 인터페이스가 멈추고 프레임이 삭제됩니다.

GUI 렌더링 스레드 : 우리에게 익숙한 페이지 그리기 및 렌더링, html、css리소스 파싱, 돔 트리 생성, 페이지 그리기를 담당하는 스레드가 모두 이 스레드를 담당합니다.
JS 엔진 스레드 : 모든 비동기 및 동기 작업의 js 구문 분석 및 실행을 담당하고 실행 스택을 유지 관리하며 먼저 동기 코드를 하나씩 처리하고 비동기 작업을 만나면 이벤트를 사용하여 스레드를 트리거합니다.

브라우저의 프로세스 및 스레드 정보는 다음과 같습니다.
여기에 이미지 설명 삽입
그 중 프런트 엔드는 주로 리소스 파싱 및 렌더링을 담당하는 브라우저 커널의 렌더링 프로세스에 중점을 두고 html、css、js이벤트 루프 및 비동기 요청도 담당합니다. .

데이터 저장: 유니앱의 캐시와 H5 캐시는 메모리에 저장되나요?

  • 네이티브 plus Storage모듈은 애플리케이션 데이터를 저장하고 읽는 데 사용되는 애플리케이션의 로컬 데이터 저장 영역을 관리합니다. 응용 프로그램 로컬 데이터 및 및 의 차이점은 데이터가 다른 도메인에서 유효하다는localStorage 것 입니다 전자는 응용 프로그램 내의 도메인 전체에서 작동할 수 있습니다 데이터 저장 기간은 영구적이며 용량 제한이 없습니다. 애플리케이션 로컬 데이터 관리 개체는 를 통해 얻을 수 있습니다.sessionStorageplus.storage

  • uni-app애플리케이션 uni.setStorage(OBJECT)(매크로태스크) 및 uni.setStorageSync(KEY,DATA)(마이크로태스크)가 데이터를 저장할 때 본질은 크기 제한이 없고 캐시가 아닌 네이티브를 사용하고 지속성을 위해 데이터베이스 파일 plus.storage에 데이터를 저장하는 것입니다.sqlite

  • 이 앱은 SQLiteIO 파일 과 같은 로컬 스토리지 솔루션 도 지원합니다.

  • H5 애플리케이션 localStoragesessionStorage데이터 스토리지의 경우 브라우저는 크기를 캐시 개념인 5M으로 제한하며 정리할 수 있습니다.

  • 애플리케이션은 Vuex상태 관리를 구현합니다.

  • 네이티브 plus.cache관리 응용 프로그램 캐시 데이터에는 webview프로그램에서 생성된 데이터만 포함되며, 확장 api(예: uni.setStorage(OBJECT)(macrotask), uni.setStorageSync(KEY,DATA)(microtask) 및 기타 API)을 사용하여 비즈니스 로직에 저장된 데이터는 포함되지 않습니다.

  • 각 애플릿은 자체적으로 제공되며 storage api데이터 저장 수명 주기는 애플릿 자체와 일치합니다. 즉, 사용자가 적극적으로 삭제하거나 특정 기간 후에 자동으로 정리되지 않는 한 데이터를 항상 사용할 수 있습니다.

  • uni-app프레임워크 구성 요소 자체로 해결할 수 없는 문제의 경우 기본 구성 요소를 사용하여 프레임워크 구성 요소를 버리고 최적화할 수 있습니다.

결국 하단 탭을 전환할 때 캐시 정리를 하도록 선택합니다.여기서 캐시 정리는 plus.cache.clear응용 프로그램의 캐시 데이터를 지우는 데 사용됩니다. webview애플리케이션 캐시 데이터 지우기는 프로그램에서 사용하여 생성된 데이터 만 포함 하고 api비즈니스 로직의 확장에 의해 저장된 데이터는 포함하지 않습니다. 아래와 같이 코드 쇼:

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

4. 확장 독서

추천

출처blog.csdn.net/sunhuaqiang1/article/details/129224778