>웹 프론트엔드 >JS 튜토리얼 >nodejs 비동기 프로그래밍_node.js에 대한 자세한 토론

nodejs 비동기 프로그래밍_node.js에 대한 자세한 토론

WBOY
WBOY원래의
2016-05-16 16:29:191484검색

현재 요구 사항에는 많은 수의 비동기 작업이 포함되어 있으며 실제 페이지는 점점 단일 페이지 애플리케이션으로 기울고 있습니다. 앞으로는 백본, 앵귤러, 녹아웃 및 기타 프레임워크를 사용할 수 있지만 비동기 프로그래밍에 대한 문제가 가장 먼저 직면해야 할 문제입니다. 노드의 등장으로 비동기 프로그래밍이 매우 뜨거운 주제가 되었습니다. 일정 기간의 연구와 실습 후에 비동기 프로그래밍에 대한 몇 가지 세부 사항이 요약됩니다.

1. 비동기 프로그래밍의 분류

비동기 문제를 해결하는 방법에는 일반적으로 직접 콜백, pub/sub 모드(이벤트 모드), 비동기 라이브러리 제어 라이브러리(예: async, when), promise, Generator 등이 포함됩니다.
1.1 콜백 기능

콜백 함수는 비동기 문제를 해결하기 위해 일반적으로 사용되는 방법으로 자주 접하고 사용되며, 이해하기 쉽고, 라이브러리나 함수에서 구현하기가 매우 쉽습니다. 이는 비동기 프로그래밍을 사용할 때 누구나 자주 사용하는 방법이기도 합니다.

하지만 콜백 함수 방식에는 다음과 같은 문제점이 있습니다.

1. 사악한 중첩 피라미드를 형성할 수 있으며 코드를 읽기가 어렵습니다.

2. 하나의 콜백 함수에만 대응할 수 있으며 이는 많은 시나리오에서 제한이 됩니다.

1.2 pub/sub 모드(이벤트)

이 모드는 이벤트 모드라고도 하는데, 이는 콜백 함수의 이벤트화이며 jQuery와 같은 라이브러리에서 매우 일반적입니다.

이벤트 게시 구독자 모델 자체에는 동기 및 비동기 호출의 문제가 없지만 노드에서는 내보내기 호출이 대부분 이벤트 루프와 비동기적으로 트리거됩니다. 이 모드는 비즈니스 로직을 분리하는 데 자주 사용됩니다. 이벤트 게시자는 등록된 콜백 함수에 주의를 기울일 필요가 없으며 메시지를 통해 데이터를 유연하게 전송할 수 있습니다.

이 모드의 장점은 다음과 같습니다. 1. 이해하기 쉽습니다. 2. 더 이상 하나의 콜백 기능으로 제한되지 않습니다.

단점: 1. 클래스 라이브러리를 사용해야 합니다. 2. 이벤트 및 콜백 함수의 순서가 매우 중요합니다.

코드 복사 코드는 다음과 같습니다.

var img = document.querySelect(#id);
img.addEventListener('load', function() {
// 이미지 로딩 완료
 …
});
img.addEventListener('error', function() {
// 문제가 발생했습니다
……
});

위 코드에는 두 가지 문제가 있습니다.

a. 실제로 img가 로드되었으며, 이때만 로드 콜백 함수가 바인딩되므로 콜백은 실행되지 않지만 해당 콜백 함수는 계속 실행되기를 바랍니다.

코드 복사 코드는 다음과 같습니다.

var img = document.querySelect(#id);
함수 로드() {
...
}
if(img.complete) {
로드();
} 그 밖의 {
img.addEventListener('load', load);
}
img.addEventListener('error', function() {
// 문제가 발생했습니다
……
});

b. 예외를 잘 처리하지 못합니다

결론: 이벤트 메커니즘은 동일한 객체에서 반복적으로 발생하는 일을 처리하는 데 가장 적합합니다. 콜백 함수가 바인딩되기 전에 이벤트 발생을 고려할 필요가 없습니다.

1.3 비동기 제어 라이브러리

현재 비동기 라이브러리에는 주로 Q, when.js, win.js, RSVP.js 등이 포함됩니다.

이 라이브러리의 특징은 코드가 선형적이고 위에서 아래로 작성될 수 있어 자연스러운 습관에 부합한다는 것입니다.

단점은 스타일이 다르기 때문에 읽기가 어렵고 학습 비용이 증가한다는 것입니다.

1.4 약속

약속은 중국어로 약속으로 번역됩니다. 개인적으로 이해하기로는 비동기 완료 후 외부 결과(성공 또는 실패)를 제공하고 결과가 변경되지 않을 것이라고 약속합니다. 즉, Promise는 작업의 최종 반환 값을 반영합니다(Promise는 작업의 단일 완료에서 반환된 최종 값을 나타냅니다). 현재 ES6 사양에는 Promise가 도입되었으며 Chrome, Firefox 등 고급 브라우저에서는 이 기본 메서드를 내부적으로 구현하여 사용하기가 매우 편리합니다.

Promise의 특징을 다음과 같은 측면에서 분석해 보겠습니다.

1.4.1 현황

세 가지 상태(보류 중, 이행됨, 거부됨)가 포함되어 있습니다. 세 가지 상태(보류 중--->이행됨, 보류 중-->거부됨) 중에서 두 가지 전환만 발생할 수 있으며 상태 전환은 한 번만 발생할 수 있습니다.

1.4.2 그다음 방법

then 메소드는 비동기 이벤트가 완료된 후 콜백 함수를 지정하는 데 사용됩니다.

이 방법은 Promise를 마법으로 가득 채우는 Promise의 Soul Method라고 할 수 있습니다. 다음과 같은 몇 가지 구체적인 발현이 있습니다.

a) then 메소드는 Promise를 반환합니다. 이를 통해 여러 비동기 작업의 직렬 작업이 가능해집니다.

위 그림의 노란색 원 1의 값 처리에 대해서는 Promise의 더 복잡한 부분입니다. 값 처리는 Promise 객체와 Non-Promise 객체의 두 가지 상황으로 구분됩니다.

value가 Promise 유형이 아닌 경우에는 value를 두 번째 Promise의 해결 매개변수 값으로 사용하고, Promise 유형인 경우에는 promise2의 상태 및 매개변수가 전적으로 값에 의해 결정된다고 볼 수 있습니다. promsie2는 완전히 가치 있는 꼭두각시이고, promise2는 서로 다른 비동기식을 연결하는 다리일 뿐입니다.

코드 복사 코드는 다음과 같습니다.

Promise.prototype.then = 함수(onFulfilled, onRejected) {
    return new Promise(function(resolve, Reject) {           //此处的 Promise标注为promise2
        핸들({
            onFulfilled: onFulfilled,
            거부됨: 거부됨,
            해결하다: 해결하다,
            거절하다: 거절하다
        })
    });
}
함수 핸들(지연됨) {
    var handlerFn;
    if(state === '충족') {
        handlerFn = deferred.onFulfilled;
    } else if(상태 === '거부됨') {
        handlerFn = deferred.onRejected;
    }
    var ret = handlerFn(값);
    deferred.resolve(ret);                           //주의, 약속2의 결심
}
함수 해결(val) {
    if(val && typeof val.then === '함수') {
        val.then(해결);                           // if val为promise对象或类promise对象时,promise2가 状态完全由val决정
        반품;
    }
    if(콜백) {                                  // 콜백为指정적 回调函数
        콜백(val);
    }
}

  b) 더 많은 것이 서로 같지 않습니다.

    异步中存에서 一个叫그때 가능한 对象, 就是指具有그런 다음 방법적 방법은 对象, 只要一个对象对象具有그런 다음 방법, 就可以对其进行转换,例如:

复主代码 代码如下:

var deferred = $('aa.ajax');      // !!deferred.then  === true
var P = Promise.resolve(지연);
p.그럼(......)

1.4.3 commonJS Promise/A规范

      目前关于Promise는 Promise/A와 Promise/A 规范,这说明关于Promise는 实现是挺复杂적입니다.

复主代码 代码如下:

then(fulfilledHandler, RejectedHandler, ProgressHandler)

1.4.4 주의사항

     一个Promise면적 回调函数是共享value 的, 에서 结果处理中value Produce为参数传递给应的回调函数, 如果value是对象,那就要小心不要轻易修改가치적 가치.

复主代码 代码如下:

var p = Promise.resolve({x: 1});
p.then(함수(발) {
    console.log('첫 번째 콜백: ' val.x );
});
p.then(함수(발) {
    console.log('두 번째 콜백: ' val.x)
})
// 첫 번째 콜백: 1
// 두 번째 콜백: 2

1.5 발전기

위의 모든 방법은 비동기 작업을 완료하기 위한 콜백 함수를 기반으로 합니다. 이는 콜백 함수를 캡슐화한 것에 지나지 않습니다. Generator는 비동기 작업을 해결하는 방법을 추가하고 더 이상 콜백 함수에 의존하지 않는 ES6에서 제안되었습니다.

Generator의 가장 큰 특징은 기능을 일시 중지하고 다시 시작할 수 있다는 것입니다. 이 기능은 비동기 작업을 해결하는 데 매우 유용합니다. Generator의 일시정지와 Promise의 예외 처리를 결합하면 비동기 프로그래밍 문제를 보다 우아하게 해결할 수 있습니다. 구체적인 구현 참조: Kyle Simpson

2. 비동기 프로그래밍 문제

2.1 예외 처리

a) 비동기 이벤트에는 비동기 요청 발행과 결과 처리라는 두 개의 링크가 포함됩니다. 이 두 링크는 ​​이벤트 루프를 통해 연결됩니다. 그런 다음 Try catch를 사용하여 예외를 캡처하는 경우 별도로 캡처해야 합니다.

코드 복사 코드는 다음과 같습니다.

시도해보세요 {
비동기이벤트(콜백)
} 잡기(err) {
 …
}

위 코드는 콜백에서 예외를 캡처할 수 없고 요청 프로세스에서만 예외를 캡처할 수 있습니다. 이로 인해 문제가 발생합니다. 요청 발행과 요청 처리가 두 사람에 의해 완료되면 예외 처리 시 문제가 발생합니까?

b) Promise는 예외 전달을 구현하여 몇 가지 이점을 제공하고 실제 프로젝트에서 코드가 차단되지 않도록 보장합니다. 하지만 비동기 이벤트가 많은 경우 어떤 비동기 이벤트가 예외를 발생시켰는지 알아내기가 쉽지 않습니다.

코드 복사 코드는 다음과 같습니다.

// 시나리오 설명: 경쟁 정보를 포함하여 CRM에 가격 경보 정보를 표시합니다. 그러나 경쟁 정보를 얻는 데 시간이 오래 걸립니다. 느린 쿼리를 피하기 위해 백엔드는 레코드를 두 개로 분할하여 별도로 가져왔습니다.
// 1단계: 경쟁 정보 외에 가격 알람 정보 가져오기
함수 getPriceAlarmData() {
새로운 Promise(function(resolve) {
반환 Y.io(url, {
메소드: 'get',
               데이터: 매개변수,
on: 함수() {
성공: 함수(id, 데이터) {
해결(alarmData);
                }
            }
        });
});
}
// 알람 정보를 얻은 후, 대회 정보를 얻습니다
getPriceAlarmData().then(함수(데이터) {
//데이터 렌더링, 대회 정보 제외
렌더링(데이터);
새로운 Promise(function(resolve) {
반환 Y.io(url, {
메소드: 'get',
              데이터: {alarmList: 데이터},
on: 함수() {
성공: function(id, compData) {
                       해결(compData);
                }
            }
        });
});
}) // 모든 데이터를 얻은 후 대회 정보를 렌더링합니다
.then(함수(데이터) {
// 공모전 정보 렌더링
렌더링(데이터)
}, 함수(err) {
//예외처리
console.log(err);
});

위 코드를 다음과 같이 변환할 수 있습니다.

코드 복사 코드는 다음과 같습니다.

시도해 보세요{
// 대회 이외의 알람 정보 얻기
var AlarmData = AlarmDataExceptCompare();
render(alarmData);
// 알람 정보를 기반으로 대회 정보 쿼리
var CompareData = getCompareInfo(alarmData);
렌더링(비교데이터);
} 캐치(err) {
console.log(err.message);
}

위의 예에서는 예외 처리가 맨 마지막에 배치되어 있으므로 특정 링크에서 예외가 발생하면 어떤 이벤트가 발생했는지 정확하게 알 수 없습니다.       

2.2 jQuery.Deferred 문제

비동기 작업은 jQuery에서도 구현되지만 구현은 주로 다음 측면에서 promise/A 사양을 준수하지 않습니다.

a. 매개변수 수: Standard Promise는 하나의 매개변수만 허용하는 반면 jQuery는 여러 매개변수를 전달할 수 있습니다.

코드 복사 코드는 다음과 같습니다.

함수 asyncInJQuery() {
var d = new $.Deferred();
setTimeout(함수() {
         d.resolve(1, 2);
}, 100);
d.promise() 반환
}
asyncInJQuery().then(function(val1, val2) {
console.log('출력: ', val1, val2);
});
// 출력: 1 2

b. 결과 처리 시 예외 처리

코드 복사 코드는 다음과 같습니다.

함수 asyncInPromise() {
새로운 Promise(function(resolve) {
반환 ​​​​ setTimeout(function() {
          var jsonStr = '{"name": "mt}';
            해결(jsonStr);
}, 100);
});
}
asyncInPromise().then(function(val) {
var d = JSON.parse(val);
console.log(d.name);
}).then(null, 함수(err) {
console.log('오류 표시: ' err.message);
});
// 오류 표시: 예기치 않은 입력 종료
함수 asyncInJQuery() {
var d = new $.Deferred();
setTimeout(함수() {
        var jsonStr = '{"name": "mt}';
         d.resolve(jsonStr);
}, 100);
d.promise() 반환
}
asyncInJQuery().then(function(val) {
var d = JSON.parse(val);
console.log(d.name);
}).then(함수(v) {
console.log('성공: ', v.name);
}, 함수(err){
console.log('오류 표시: ' err.message);
});
//Uncaught SyntaxError: 예기치 않은 입력 종료

이를 통해 Promise는 콜백 함수에 대한 결과 처리를 수행하고 콜백 함수 실행 중에 예외를 캡처할 수 있지만 jQuery.Deferred는 그렇지 않음을 알 수 있습니다.

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.