2022년 React Native에서 PouchDB@7을 사용하는 성능 좋은 방법

안녕하세요, 여기 있습니다.
저는 사용자 데이터를 CouchDB와 동기화하는 React Native 앱을 개발해 왔습니다. 앱 이름은 Inkdrop 입니다.

과거에 React Native에서 PouchDB를 사용하는 방법에 대한 여러 게시물을 게시했습니다.



  • 이 문서는 RN에서 PouchDB를 사용하기 위한 업데이트입니다.

    다행히도 PouchDB은 여전히 ​​유지되고 있으며 최근에 v7.3.0 🎉을 출시했습니다. 커뮤니티의 노력에 감사드립니다.

    TL; DR


  • 2~5배 속도 향상!
  • 라이브러리 수정이 적고 설정이 간단함
  • 첨부 파일이 더 이상 지원되지 않음
  • 사용법

  • JSI 기반 SQLite 드라이버 사용



    Oscar Franco는 훌륭한 SQLite 드라이버react-native-quick-sqlite를 만들었습니다. 이 드라이버는 SQL 쿼리를 실행하는 저수준 API와 JSI을 통한 빠른 바인딩을 제공합니다. JSI는 기존 RN 브리지보다 오버헤드가 작습니다.
    따라서 이전에 PouchDB가 RN에서 작동하도록 만든 react-native-sqlite-2 보다 훨씬 빠릅니다.

    내 프로젝트에서 사용하고 싶어서 WebSQL과 호환되는 quick-sqlite를 만드는 얇은 래퍼인 react-native-quick-websql을 만들었습니다. 완벽하게 작동합니다!

    성능 향상 방법은 나중에 설명하겠습니다.

    NULL 문자 문제 해결(다시)



    React Native에는 여전히 문제가 있습니다. \u0000 로 문자열 데이터를 저장할 수 없습니다.
  • JavaScript strings with NULL character are not handled properly when passed to Native Modules · Issue #12731 · facebook/react-native

  • 이 문제를 방지하기 위해 NULL 문자는 다음과 같이 react-native-sqlite-2에서 이스케이프/이스케이프 해제됩니다.

    function escapeBlob(data: any) {
      if (typeof data === 'string') {
        return data
          .replace(/\u0002/g, '\u0002\u0002')
          .replace(/\u0001/g, '\u0001\u0002')
          .replace(/\u0000/g, '\u0001\u0001')
      } else {
        return data
      }
    }
    


    그러나 성능에 영향을 미치기 때문에 이상적이지 않습니다.

    PouchDB는 pouchdb-collate에서 MapReduce로 문서를 인덱싱하기 위해 내부적으로 \u0000를 사용합니다.

    / convert the given key to a string that would be appropriate
    // for lexical sorting, e.g. within a database, where the
    // sorting is the same given by the collate() function.
    function toIndexableString(key) {
      var zero = '\u0000';
      key = normalizeKey(key);
      return collationIndex(key) + SEP + indexify(key) + zero;
    }
    


    \u0000 이어야 하는지 모르겠어서 제로 마커를 \u0003 로 변경했습니다.
  • https://github.com/craftzdog/pouchdb-react-native/commit/228f68220fe31236f6630b71c030eef29ae6e7a8

  • 그리고 그것이 효과가 있다는 것이 밝혀졌습니다!
    이제 NULL 문자를 이스케이프 처리하는 오버헤드가 제거되었습니다.

    2~5배 더 빠릅니다 💨



    내 Google Pixel 5에서 테스트한 결과 엄청나게 빠른 것으로 나타났습니다. 다음은 빠른 벤치마크입니다.



    sqlite-2
    빠른 SQLite + 빠른 웹 SQL


    38개 문서에 대한 캐시되지 않은 쿼리
    4,510ms
    984ms

    38개 문서에 대한 캐시된 쿼리
    275ms
    75ms

    1422 문서에 대한 캐시된 쿼리
    636ms
    206ms


    PouchDB는 MapReduce를 수행하여 design documents을 기반으로 문서를 인덱싱합니다.
    이것이 첫 번째 쿼리가 오랜 시간이 걸리는 이유입니다.
    하지만 작은 오버헤드 덕분에 이제 약 4~5배 더 빨라졌습니다.

    내 앱의 새 버전을 빨리 출시하고 싶습니다.

    첨부 파일은 더 이상 지원되지 않습니다.



    이전 작업에서는 PouchDB에 첨부 파일을 저장할 수 있도록 하는 데 중점을 두었습니다. 그러나 I no longer store them in PouchDB 이므로 요구 사항이 삭제되었습니다.
    하지만 이렇게 하면 위에서 언급한 pouchdb-collate를 제외한 공식 PouchDB 패키지를 간단히 사용할 수 있습니다.

    사용하는 방법


    설치



    개발 패키지 설치:

    yarn add -D babel-plugin-module-resolver
    


    polyfill 패키지를 설치합니다.

    yarn add events react-native-get-random-values react-native-quick-base64
    


    pouchdb 패키지를 설치합니다.

    yarn add pouchdb-core pouchdb-replication pouchdb-mapreduce pouchdb-adapter-http
    


    패치된 패키지를 설치합니다.

    yarn add @craftzdog/pouchdb-collate-react-native
    


    스토리지 어댑터 패키지 설치:

    yarn add pouchdb-adapter-react-native-sqlite react-native-quick-sqlite react-native-quick-websql
    



  • react-native-quick-sqlite - SQLite용 JSI를 통한 빠른 바인딩

  • react-native-quick-websql - quick-sqlite용 WebSQL 래퍼

  • pouchdb-adapter-react-native-sqlite - 이 두 모듈이 있는 SQLite용 PouchDB 어댑터
  • CocoaPods 설치:

  • npx pod-install
    


    구성



    만들기 shim.js:

    import {shim} from 'react-native-quick-base64'
    
    shim()
    
    // Avoid using node dependent modules
    process.browser = true
    


    그런 다음 index.js 시작 부분에 필요합니다.

    다음과 같이 babel.config.js를 편집합니다.

    module.exports = {
      presets: ['module:metro-react-native-babel-preset'],
      plugins: [
        [
          'module-resolver',
          {
            alias: {
              'pouchdb-collate': '@craftzdog/pouchdb-collate-react-native',
            },
          },
        ],
      ],
    }
    


    초기화



    다음과 같이 pouchdb.ts를 만듭니다.

    import 'react-native-get-random-values'
    import PouchDB from 'pouchdb-core'
    import HttpPouch from 'pouchdb-adapter-http'
    import replication from 'pouchdb-replication'
    import mapreduce from 'pouchdb-mapreduce'
    import SQLiteAdapterFactory from 'pouchdb-adapter-react-native-sqlite'
    import WebSQLite from 'react-native-quick-websql'
    
    const SQLiteAdapter = SQLiteAdapterFactory(WebSQLite)
    
    export default PouchDB.plugin(HttpPouch)
      .plugin(replication)
      .plugin(mapreduce)
      .plugin(SQLiteAdapter)
    


    그런 다음 평소와 같이 가져와서 사용합니다.

    import PouchDB from './pouchdb'
    
    const db = new PouchDB('mydb.db', {
      adapter: 'react-native-sqlite'
    })
    


    그게 다야!

    제한 및 디버깅



    라이브러리가 동기 네이티브 메서드 액세스에 JSI를 사용하므로 원격 디버깅(예: Chrome 사용)은 더 이상 가능하지 않습니다.
    대신 Flipper 을 사용해야 합니다.

    유용하고 도움이 되길 바랍니다.


  • 나를 따라와 &
  • Inkdrop — Markdown note-taking app

  • 좋은 웹페이지 즐겨찾기