자 바스 크 립 트 비동기 코드 최적화

머리말
실제 인 코딩 에서 우 리 는 자 바스 크 립 트 코드 가 비동기 적 으로 실행 되 는 장면 을 자주 만 날 수 있다.예 를 들 어 자 바스 크 립 트 의 호출,타이머 의 사용 등 이다.이런 장면 에서 도 이런 생각 지도 못 한 bug 나 나 쁜 코드 세 션 이 자주 나타난다.그러면 자 바스 크 립 트 비동기 코드 를 잘 처리 하 는 것 은 비동기 프로 그래 밍 의 중요 한 전제 가 된다.다음은 우리 가 문제 에서 출발 하여 당신 의 비동기 코드 를 한 걸음 한 걸음 보완 하 겠 습 니 다.
비동기 문제
1.지옥 으로 돌아간다
우선,우 리 는 비동기 프로 그래 밍 에서 가장 흔히 볼 수 있 는 문 제 를 살 펴 보 자.바로 지옥 으로 돌아 가 는 것 이다.그것 의 출현 은 비동기 코드 실행 시간의 불확실 성과 코드 간 의 의존 관계 로 인 한 것 이다.예 를 들 어:

//        ,       ,                
$('#box').animate({width: '100px'}, 1000, function(){
  $('#box').animate({height: '100px'}, 1000, function(){
    $('#box').animate({left: 100}, 1000);
  });
});
첫 번 째 애니메이션 이 언제 시작 되 거나 언제 끝 날 지 모 르 기 때문에 우 리 는 두 번 째 애니메이션 의 실행 내용 을 첫 번 째 애니메이션 의 끝 사건 에 넣 었 고 세 번 째 애니메이션 을 두 번 째 애니메이션 의 끝 사건 에 넣 었 다.이때 이런 애니메이션 이 많 으 면 지옥 으로 돌아 갈 것 이다.
2.이상 포획
지옥 으로 돌아 가 는 것 외 에 비동기 코드 에서 이상 을 포착 하 는 것 도 귀 찮 습 니 다.포획 방법 을 수 동 으로 설정 해 야 할 수도 있 습 니 다.

try {
  throw new Error('fail');
} catch (e) {
  console.log(e);
}
이러한 코드 작성 은 우리 가 원 하 는 것 이 아니 라 유지 에 불리 할 뿐만 아니 라 어느 정도 에 좋 은 자바 script 인 코딩 규범 에 위배 된다.
해결 방안
그러면 우 리 는 어떻게 우아 하 게 우리 의 비동기 코드 를 쓸 수 있 습 니까?나 는 주로 다음 과 같은 다섯 가지 흔 한 방안 을 열거 했다.
1. callback
콜백 은 말 그대로 리 셋 입 니 다.그러나 리 셋 내용 을 비동기 적 인 방법 에 두 는 것 이 아니 라 외부 리 셋 함수 에 넣 는 것 입 니 다.예 를 들 어 문제 1 의 코드 는 저희 가 콜백 을 통 해 이렇게 될 수 있 습 니 다.

$('#box').animate({width: '100px'}, 1000, autoHeight);

function autoHeight() {
  $('#box').animate({height: '100px'}, 1000, autoLeft);
}

function autoLeft() {
  $('#box').animate({left: 100}, 1000);
}
이렇게 해서 우 리 는 비동기 적 으로 보 이 는 코드 가 동기 화 된 쓰기 로 바 뀌 었 고 겹 쳐 서 끼 워 넣 는 쓰기 도 피 했 으 며 유창 해 보 였 다.동시에 callback 을 사용 하 는 것 도 비동기 프로 그래 밍 의 가장 기본 적 이 고 핵심 적 인 해결 방향 이다.
2. Promise
콜백 을 바탕 으로 Promise 는 현재 광범 위 하 게 운용 되 고 있 으 며 비동기 프로 그래 밍 의 해결 방안 으로 전통 적 인 리 셋 함수 해결 방안 보다 더욱 합 리 적 이 고 강력 하 다.ES6 를 잘 아 는 친구 들 은 낯 설 지 않 을 거 라 고 믿 습 니 다.
예 를 들 어 우 리 는 지금 이런 장면 이 있 습 니 다.우 리 는 다른 단계 로 그림 을 불 러 와 야 합 니 다.그림 을 불 러 오 는 데 성공 한 후에 조작 을 해 야 합 니 다.여기 서 저 는 리 셋 함수 나 논 리 를 그림 의 성공 사건 에 쓰 고 싶 지 않 습 니 다.그러면 Promise 로 우 리 는 이렇게 쓸 수 있 습 니 다.

let p = new Promise((resolve, reject) => {
  let img = new Image(); //       

  //         
  img.onload = function() {
    resolve(img); //       
  };

  //         
  img.onerror = function() {
    reject(new Error('load error')); //     
  };

  img.src = 'xxx'; //     
});

// Promise then  
p
.then(result => {
  $('#box').append(result); //              
})
.catch(error => {
  console.log(error); //     
})
Promise 를 통 해 저 희 는 그림 을 불 러 오 는 논리 와 성공 또는 실패 후의 처리 논 리 를 분리 하여 리 셋 함수 의 끼 워 넣 기 를 체인 호출 으로 바 꾸 었 습 니 다.또한 Promise 의 catch 이벤트 리 셋 을 사용 하여 이상 한 캡 처 를 하 는 것 도 편리 합 니 다.
물론 여러 비동기 요청 이 실 행 될 때 까지 기다 리 려 면 Promise.all 방법 을 사용 할 수 있 습 니 다.예 를 들 어:

let p = Promise.all([p1, p2, p3]); //   p1、p2、p3  Promise  

p.then(result => console.log(result));
물론 Promise 도 해당 하 는 단점 이 있 습 니 다.예 를 들 어 다음 then 리 셋 은 이전 then 에서 돌아 온 데이터 만 얻 을 수 있 고 층 을 넘 어 얻 을 수 없 으 며 대량의 then 리 셋 도 코드 를 쉽게 유지 하지 못 할 것 입 니 다.
3. Generator
Promise 와 마찬가지 로 Generator 함수 도 ES6 가 제공 하 는 비동기 프로 그래 밍 솔 루 션 입 니 다.이 는 스 트 리밍 대상 으로 돌아 갑 니 다.비동기 작업 이 멈 춰 야 할 곳 에서 우 리 는 yield 문 구 를 사용 할 수 있 습 니 다.예 를 들 어:

function* getData() {
  let result = yield fetch("xxx"); //   ajax,yield        Thunk     Promise   

  console.log(result);
}

//   
let g = getData();
let result = g.next(); // { value: [object Promise], done: false }

result.value.then(data => {
  return data.json();
}).then(data => {
  g.next(data);
});
Generator 에서 yield 를 만난 곳 은 일시 정지 되 기 때문에 next 방법 을 수 동 으로 호출 해 야 합 니 다.next 반환 값 의 value 속성 은 바로 우리 가 필요 로 하 는 데이터 입 니 다.여 기 는 fetch 방법 으로 돌아 오 는 Promise 대상 이기 때문에 then 리 셋 을 사용 하고 마지막 으로 g.next(data)를 호출 하여 데 이 터 를 끝내 고 출력 해 야 합 니 다.
Generator 함수 의 단점 은 우리 가 매번 yield 문 구 를 실행 할 때마다 수 동 으로 next 를 진행 해 야 하기 때문에 매우 편리 하지 않다 는 것 이다.
4. co
위의 Generator 함수 가 next 방법 을 수 동 으로 실행 해 야 하 는 문 제 를 해결 하기 위해 TJ Holowaychuk 대신 은 co 함수 라 이브 러 리 를 작 성 했 습 니 다.Generator 함수 가 자동 으로 실 행 될 수 있 습 니 다.예 를 들 어 우리 가 이렇게 해 야 합 니 다.

let files = function* (){
  var f1 = yield readFile('/xxx/xxx'); //   file1  
  var f2 = yield readFile('/xxx/xxx'); //   file2  

  console.log(f1.toString());
  console.log(f2.toString());
};

files.next(); //   yield
files.next(); //   yield
co 사용 후:

var co = require('co');

co(files);
 
co 함수 가 Promise 대상 을 되 돌려 주기 때문에 then 방법 으로 리 셋 함 수 를 추가 할 수 있 습 니 다.

co(files).then(() => {
 console.log('    ');
});
마지막 으로 next 방법 을 수 동 으로 실행 하지 않 고 읽 은 파일 도 출력 하 는 것 을 볼 수 있 습 니 다.
co 모듈 은 Generator 함수 가 실행 기 에 의존 해 야 하 는 문 제 를 해결 하 는 데 도움 을 주 었 지만 사용 할 때 우 리 는 하나의 모듈 을 추가 로 도입 해 야 합 니 다.그러면 더욱 편리 한 방법 으로 해결 할 수 있 습 니까?계속 내 려 다 봐.
5. async and await
상기 4 가지 방식 으로 자바 script 비동기 프로 그래 밍 문 제 를 해결 할 수 있 는 것 외 에 ES7 은 더욱 편리 한 async 함수 와 await 명령 을 제공 합 니 다.알 아 보 시 겠 습 니까?
사실 async 는 Generator 함수 의 문법 사탕 으로 다른 점 은 실행 기 를 내장 한 것 입 니 다.즉,async 함수 자체 집행 기 입 니 다.아래 의 예 를 보 세 요.

let p1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve(1);
  }, 1000);
});

let p2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve(2); 
  }, 1000);
});

async function waitFn() {
  let a = await p1; // await        Promise          ,              Promise  
  let b = await p2;

  return a + b
}

// async        Promise   ,    then          
waitFn().then(result => {
  console.log(result); // 2s   3
});
async 함수 내부 return 문 구 를 되 돌려 주 는 값 은 then 방법 으로 함수 의 매개 변수 가 됩 니 다.그래서 이것 은 co 로 감 싼 Generator 함수 와 같 습 니 다.*를 async 로 바 꾸 고 yield 를 await 로 바 꾸 었 습 니 다.
async and await 는 ES7 에서 가장 중요 한 특성 이 라 고 할 수 있 습 니 다.단점 도 있 지만 비동기 코드 를 처리 하 는 것 에 비해 비교적 능숙 합 니 다.
결어
본 고 는 자바 script 비동기 코드 를 잘 처리 하 는 다섯 가지 흔 한 방식 을 간단하게 소개 했다.모든 방식 은 사용 과 존재 하 는 조건 과 필요 성 이 있 고 관심 이 있 는 학생 들 은 이 를 단독 적 으로 확대 하고 탐구 할 수 있다.모든 방식 이 각자 의 장점 을 이해 하고 파악 하 며 활용 해 야 비동기 프로 그래 밍 이 가 져 온 쾌감 을 누 릴 수 있다.
위 에서 말 한 것 은 소 편 이 여러분 에 게 소개 한 자 바스 크 립 트 비동기 코드 의 최적화 와 상세 한 통합 입 니 다.여러분 에 게 도움 이 되 기 를 바 랍 니 다.만약 에 궁금 한 점 이 있 으 면 저 에 게 메 시 지 를 남 겨 주세요.소 편 은 제때에 여러분 에 게 답 할 것 입 니 다.여기 서도 저희 사이트 에 대한 여러분 의 지지 에 감 사 드 립 니 다!

좋은 웹페이지 즐겨찾기