자바 스크립트로 프런트 엔드 코드의 성능을 향상시키는 몇 가지 방법

자바 스크립트 칼럼은 프런트 엔드 코드의 성능을 향상시키는 몇 가지 방법을 소개합니다.
무료 추천 : JavaScript (동영상)
는 과거 개발 경험에서 모든 종류의 이상한 버그를 다루었으며 코드 견고성 (견고성)이 작업 효율성과 삶의 질을 향상시키는 중요한 지표임을 깨달았습니다.이 기사는 주로 코드 견고성 향상을 구성합니다. 생각.

전에 코드 견고성에 대한 기사를 분류했습니다.

JavaScript의 단위 테스트를 엄격하게 작성
코드에 로그인하는 방법
이 기사에서는 단위 테스트 및 로깅 외에도 JavaScript 코드의 견고성을 개선하는 데 도움이되는 몇 가지 방법을 계속 탐색합니다.

객체에보다 안전하게 액세스하고
인터페이스 데이터를 신뢰하지 마세요.
프런트 엔드에서 전달한 매개 변수를 신뢰하지 말고 백그라운드에서 반환 된 데이터를 신뢰하지 마세요.

예를 들어 문서 규칙에 따른 특정 api / xxx / list 인터페이스

{

    code: 0,

    msg: "",

    data: [     // ... 具体数据

    ],

};复制代码

프런트 엔드 코드는 다음과 같이 작성 될 수 있습니다.

const {code, msg, data} = await fetchList()

data.forEach(()=>{})复制代码

백그라운드에서 반환 된 데이터가 배열이라고 가정하기 때문에 공동 디버깅 중에 일부 예외가 누락 된 경우 data.forEach를 직접 사용합니다.

데이터가없는 경우 데이터가 [] 빈 배열을 반환 할 것으로 예상되지만 백그라운드 구현은 데이터 필드를 반환하지 않습니다.
이후 인터페이스 업데이트, 데이터가 배열에서 사전으로 변경되고 시간 프런트 엔드입니다.
이 시간은, data.forEach를 사용합니다. 오류를보고합니다,

포착되지 않은 TypeError : data.forEach는 함수가 아닙니다.

따라서 백그라운드 인터페이스의 반환 값이 직접 사용되는 이러한 장소에서는 유형 감지를 추가하는 것이 가장 좋습니다.

Array.isArray(data) && data.forEach(()=>{})复制代码

마찬가지로 백엔드가 프런트 엔드 요청 매개 변수를 처리 할 때 관련 유형 감지도 수행해야합니다.

Null 병합 연산자
JavaScript의 동적 특성으로 인해 xyz와 같은 개체 속성을 쿼리 할 때 x와 y가 있는지 확인하는 것이 가장 좋습니다.

let z = x && x.y && x.y.z复制代码

이것을 자주 작성하는 것은 매우 번거롭고 dart의 객체 속성에 안전하게 액세스하는 것이 훨씬 더 간단합니다.

var z = a?.y?.z;复制代码

ES2020에서는 dart와 같은 객체 속성에 안전하게 액세스하는 것과 동일한 기능을 수행 할 수있는 ?? 및?. 연산자를 포함한 null 병합 연산자 초안이 제안되었습니다. 이제 최신 버전의 Chrome을 열어 테스트 할 수 있습니다.
여기에 사진 설명 삽입

그 전에는 객체 속성을 안전하게 얻기 위해 메서드를 캡슐화 할 수 있습니다.

function getObjectValueByKeyStr(obj, key, defaultVal = undefined) {    if (!key) return defaultVal;    let namespace = key.toString().split(".");    let value,

        i = 0,

        len = namespace.length;    for (; i < len; i++) {

        value = obj[namespace[i]];        if (value === undefined || value === null) return defaultVal;

        obj = value;

    }    return value;

}var x = { y: { z: 100,},};var val = getObjectValueByKeyStr(x, "y.z");// var val = getObjectValueByKeyStr(x, "zz");console.log(val);复制代码

프런트 엔드는 필연적으로 다양한 브라우저와 다양한 장치를 처리해야합니다. 특히 ES2015 기능을 사용하여 코드를 개발하는 데 익숙해 졌기 때문에 매우 중요한 문제는 호환성입니다. Polyfill은 대부분의 문제를 해결하는 데 도움이 될 수 있습니다..

예외 처리
참조를 기억하십시오 .

JS 오류 처리 MDN
js는 UI를위한 통합 된 예외 처리 솔루션을 구축합니다.이 기사 시리즈는 매우 잘 작성되어 있습니다.
예외 처리는 코드 견고성을위한 기본 보장 입니다. 예외 처리에는 두 가지 측면이 있습니다.

적절한 오류 처리는 사용자 경험을 요약 할 수 있으며 코드가 잘못되었을 때 사용자에게 적절하게 메시지
를 표시 할 수 있습니다 . 오류 처리를 캡슐화하여 개발 량을 줄이고 코드에서 오류 처리를 분리 할 수 있습니다 .
오류 객체.
사용자 정의 오류 객체는 다음과 같을 수 있습니다. throw 문을 통해 발생합니다.

// Create an object type UserExceptionfunction UserException (message){  // 包含message和name两个属性

  this.message=message;  this.name="UserException";

}// 覆盖默认[object Object]的toStringUserException.prototype.toString = function (){  return this.name + ': "' + this.message + '"';

}// 抛出自定义错误function f(){    try {        throw new UserException("Value too high");

    }catch(e){        if(e instanceof UserException){            console.log('catch UserException')            console.log(e)

        }else{            console.log('unknown error')            throw e

        }

    }finally{        // 可以做一些退出操作,如关闭文件、关闭loading等状态重置

        console.log('done')        return 1000 // 如果finally中return了值,那么会覆盖前面try或catch中的返回值或异常

    }

}

f()复制代码

동기화 코드 동기화 코드의
경우 책임 체인 모드를 사용하여 오류를 캡슐화 할 수 있습니다. 즉, 현재 함수가 오류를 처리 할 수있는 경우 catch에서 처리됩니다. 해당 오류를 처리 할 수 ​​없으면 catch가 throw됩니다. 다시 상위 수준으로

function a(){    throw 'error b'}// 当b能够处理异常时,则不再向上抛出function b(){    try{

        a()

    }catch(e){        if(e === 'error b'){            console.log('由b处理')

        }else {            throw e

        }

    }

}function main(){    try {

        b()

    }catch(e){        console.log('顶层catch')

    }

}复制代码

비동기 코드
catch는 비동기 코드에서 발생한 예외를 가져올 수 없기 때문에 책임 체인을 실현하기 위해 예외 처리가 콜백 함수를 통해 비동기 작업에 전달되어야합니다.

function a(errorHandler) {    let error = new Error("error a");    if (errorHandler) {

        errorHandler(error);

    } else {        throw error;

    }

}function b(errorHandler) {    let handler = e => {        if (e === "error b") {            console.log("由b处理");

        } else {

            errorHandler(e);

        }

    };    setTimeout(() => {

        a(handler);

    });

}let globalHandler = e => {    console.log(e);

};

b(globalHandler);复制代码

Prmise
Promise 의 예외 처리 에는 보류, 거부 및 이행의 세 가지 상태 만 포함됩니다.

let promise2 = promise1.then(onFulfilled, onRejected)复制代码

다음은 예외를 던지는 약속에 대한 몇 가지 규칙입니다.

function case1(){    // 如果promise1是rejected态的,但是onRejected返回了一个值(包括undifined),那么promise2还是fulfilled态的,这个过程相当于catch到异常,并将它处理掉,所以不需要向上抛出。

    var p1 = new Promise((resolve, reject)=>{        throw 'p1 error'

    })

 

    p1.then((res)=>{        return 1

    }, (e)=>{        console.log(e)        return 2

    }).then((a)=>{        // 如果注册了onReject,则不会影响后面Promise执行

        console.log(a) // 收到的是2

    })

}function case2(){    //  在promise1的onRejected中处理了p1的异常,但是又抛出了一个新异常,,那么promise2的onRejected会抛出这个异常

    var p1 = new Promise((resolve, reject)=>{        throw 'p1 error'

    })

    p1.then((res)=>{        return 1

    }, (e)=>{        console.log(e)        throw 'error in p1 onReject'

    }).then((a)=>{}, (e)=>{        // 如果p1的 onReject 抛出了异常

        console.log(e)

    })

}function case3(){    // 如果promise1是rejected态的,并且没有定义onRejected,则promise2也会是rejected态的。

    var p1 = new Promise((resolve, reject)=>{        throw 'p1 error'

    })

 

    p1.then((res)=>{        return 1

    }).then((a)=>{        console.log('not run:', a)

    }, (e)=>{        // 如果p1的 onReject 抛出了异常

        console.log('handle p2:', e)

    })

}function case4(){    // // 如果promise1是fulfilled态但是onFulfilled和onRejected出现了异常,promise2也会是rejected态的,并且会获得promise1的被拒绝原因或异常。

    var p1 = new Promise((resolve, reject)=>{

        resolve(1)

    })

    p1.then((res)=>{        console.log(res)        throw 'p1 onFull error'

    }).then(()=>{}, (e)=>{        console.log('handle p2:', e)        return 123

    })

}复制代码

따라서 onRejected에서 현재 프라 미스의 오류를 처리 할 수 ​​있습니다. 그렇지 않은 경우 다음 프라 미스로 던질 수 있습니다.

async
async / await는 본질적으로 promise의 구문 설탕이므로 promise의 유사한 캡처 메커니즘을 사용할 수도 있습니다.

function sleep(cb, cb2 =()=>{},ms = 100) {

    cb2()    return new Promise((resolve, reject) => {        setTimeout(() => {            try {

                cb();

                resolve();

            }catch(e){

                reject(e)

            }

        }, ms);

    });

}// 通过promise.catch来捕获async function case1() {    await sleep(() => {        throw "sleep reject error";

    }).catch(e => {        console.log(e);

    });

}// 通过try...catch捕获async function case2() {    try {        await sleep(() => {            throw "sleep reject error";

        })

    } catch (e) {        console.log("catch:", e);

    }

}// 如果是未被reject抛出的错误,则无法被捕获async function case3() {    try {        await sleep(()=>{}, () => {            // 抛出一个未被promise reject的错误

            throw 'no reject error'

        }).catch((e)=>{            console.log('cannot catch:', e)

        })

    } catch (e) {        console.log("catch:", e);

    }

}复制代码

보다 안정적인 타사 모듈이
날짜 형식 지정과 같은 비교적 작은 기능을 구현할 npm에서 성숙한 라이브러리를 찾는 데 익숙하지 않을 수 있지만 개발 시간이나 테스트 사례가 부족하여 기능 패키지를 직접 작성하는 데 익숙하지 않을 수 있습니다. 고려되지 않은 경계 조건이 발생하면 BUG가 나타나기 쉽습니다.

이것은 홀수인지 여부를 확인하는 패키지 인 isOdd와 같은 일부 작은 모듈이 npm에 자주 나타나고 주간 다운로드 볼륨은 실제로 600,000이라는 사실이기도합니다.
여기에 사진 설명 삽입

좀 더 성숙한 라이브러리를 사용하는 매우 중요한 이유 중 하나는 이러한 라이브러리가 종종 많은 테스트 케이스 및 커뮤니티에서 테스트되며보다 편리한 도구 코드보다 확실히 안전하다는 것입니다.

개인 경험의 예는 다음과 같습니다. UA에 따르면 사용자의 현재 장치 액세스 권한을 판단하는 일반적인 아이디어는 일반 사용자를 통해 일치시키는 것입니다.

export function getOSType() {  const ua = navigator.userAgent  const isWindowsPhone = /(?:Windows Phone)/.test(ua)  const isSymbian = /(?:SymbianOS)/.test(ua) || isWindowsPhone  const isAndroid = /(?:Android)/.test(ua)  // 判断是否是平板

  const isTablet =    /(?:iPad|PlayBook)/.test(ua) ||

    (isAndroid && !/(?:Mobile)/.test(ua)) ||

    (/(?:Firefox)/.test(ua) && /(?:Tablet)/.test(ua))  // 是否是iphone

  const isIPhone = /(?:iPhone)/.test(ua) && !isTablet  // 是否是pc

  const isPc = !isIPhone && !isAndroid && !isSymbian && !isTablet  return {

    isIPhone,

    isAndroid,

    isSymbian,

    isTablet,

    isPc

  }

}复制代码

온라인에 접속 한 후 일부 Xiaomi 태블릿 사용자의 논리적 판단이 비정상임을 발견했으며 로그 북은 UA가

"Mozilla/5.0 (Linux; U; Android 8.1.0; zh-CN; MI PAD 4 Build/OPM1.171019.019) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 Quark/3.8.5.129 Mobile Safari/537.36复制代码

정기 판정에 MI PAD를 추가하여 일시적으로 고쳐도 나중에 다른 기기의 특수 UA가 나오면 어떻게 되나요? 따라서 내 경험으로 글을 쓸 때 모든 문제를 고려하고 나중에 모바일 감지 라이브러리로 교체하는 것은 어렵습니다.

모듈 사용의 단점은

파일 종속성 볼륨 증가, 패키징 시간 증가 등이 발생할 수 있습니다.이 문제는 구성을 패키징하고 자주 변경되지 않는 타사 모듈을 공급 업체 파일로 패키징하여 해결할 수 있습니다. 구성 캐시.
일부 프로젝트에서는 타사 모듈이 필요할 수 있습니다. 보안 고려 사항으로 인해 감소 될 수 있습니다. 사용 또는
모듈 선택 시간 동안 소스 코드 검토 과정에 필요한 것은 안정성, 이전 버전과의 호환성, 해결되지 않은 문제 및 기타 문제를 포함한 다양한 고려 사항이어야합니다. 더 나은 도구 모듈을 선택한 후에는 비즈니스 로직에 더 집중할 수 있습니다.

로컬 구성 파일
개발 환경에서 일부 로컬 스위치 구성 파일이 필요할 수 있습니다. 이러한 구성은 로컬 개발 중에 만 존재하며 코드베이스를 입력하지 않으며 다른 동료의 구성과 충돌하지 않습니다.

다른 동료들이 인터페이스를 개발하고 디버깅하는 것이 편리하도록 git 저장소에 mock 템플릿을 호스팅하는 것이 좋습니다. 문제가 발생하면 로컬에서 mock 파일을 가져 오는 스위치가 필요할 수 있습니다.

다음은 일반적인 방법입니다. 새 로컬 구성 파일 config.local.js를 만든 다음 관련 구성 정보를 내 보냅니다.

// config.local.jsmodule.exports = {  needMock: true}复制代码

.gitignore의 파일을 무시하십시오.

config.local.js复制代码

그런 다음 try ... catch ...를 통해 모듈을로드합니다. 파일이 코드베이스에 들어 가지 않았기 때문에 코드가 다른 곳에서 업데이트 될 때 catch 프로세스에 들어가고 로컬 개발은 일반 모듈 도입 프로세스에 들어갑니다.

// mock/entry.jstry {  const { needMock } = require('./config.local')  if (needMock) {    require('./index') // 对应的mock入口

    console.log('====start mock api===')

  }

} catch (e) {  console.log('未引入mock,如需要,请创建/mock/config.local并导出 {needMock: true}')

}复制代码

마지막으로 전체 애플리케이션의 엔트리 파일에서 개발 환경을 결정하고 가져옵니다.

if (process.env.NODE_ENV === 'development') {  require('../mock/entry')

}复制代码

이렇게하면 코드를 제출하기 전에 해당 구성 변경 사항에 대해 주석을다는 것을 잊지 않고 로컬 개발 중에 다양한 구성을 행복하게 수행 할 수 있습니다 ~

코드 검토
참조 :

코드 리뷰는 씁쓸하지만 흥미로운 연습입니다.
코드 리뷰는 온라인에 들어가기 전에 필요한 단계 여야합니다. CR의 주요 역할은

요구 사항 이해에 편차가 있는지 확인하고 랭 글링을 피할 수 있습니다.

중복 코드, 변수 이름 지정 및 오버 캡슐화 등을 포함하여 코드 품질을 최적화합니다. 최소한 코드 작성자 외에도 검토자가 관련 논리를 이해할 수 있는지 확인해야합니다.

장기적인 유지 관리 및 반복이 필요한 프로젝트의 경우 모든 커밋 및 병합이 매우 중요하므로 코드를 병합하기 전에 변경된 코드를 처음부터 확인하는 것이 가장 좋습니다. 소규모 팀에 속해 있거나 리뷰어를 찾을 수 없더라도 합병을 진지하게 생각하십시오.

요약
이 기사는 주로 JavaScript 코드의 견고성을 개선하기위한 몇 가지 방법을 구성합니다.

객체 속성에 안전하게 액세스하여 데이터 예외로 인한 코드 오류를 방지합니다. 예외를
포착하고 예외를 처리하거나 책임 체인을 통해보고합니다.
보다 안정적이고 안전한 타사 모듈을
사용하고 모든 병합을 심각하게 고려하고 온라인으로 전환하기 전에 코드를 확인합니다. .
또한, 좋은 프로그래밍 습관을 개발하기 위해해야하는만큼 가능한 한 다양한 경계 상황을 고려하십시오.
이 기사는 PHP 중국어 웹 사이트의 자바 스크립트 칼럼에서 발췌 한 것입니다 : https://www.php.cn/course/list/17.html

추천

출처blog.csdn.net/Anna_xuan/article/details/110237897