node.js 콜백 피라미드 다루기


9

방금 노드를 사용하기 시작했으며 빠르게 주목 한 것은 콜백이 얼마나 빨리 바보 같은 수준의 들여 쓰기까지 만들 수 있는지입니다.

doStuff(arg1, arg2, function(err, result) {
    doMoreStuff(arg3, arg4, function(err, result) {
        doEvenMoreStuff(arg5, arg6, function(err, result) {
            omgHowDidIGetHere();
        });
    });
});

공식 스타일 가이드는 별도의 기능을 각각의 콜백을 넣어라고하지만 개체가 모두 통과해야한다와 같은 단일 객체가 사용할 수있는 여러 가지 층 위에서 아래 수준에서 선언 클로저의 사용에 지나치게 제한적인 것, 그리고 만들기 중간 콜백.

여기서 도움을주기 위해 함수 범위를 사용해도 되나요? 전역 객체에 액세스해야하는 모든 콜백 함수를 해당 객체를 선언하는 함수 안에 넣으면 클로저로 이동합니까?

function topLevelFunction(globalishObject, callback) {

    function doMoreStuffImpl(err, result) {
        doMoreStuff(arg5, arg6, function(err, result) {
            callback(null, globalishObject);
        });
    }

    doStuff(arg1, arg2, doMoreStuffImpl);
}

그리고 더 많은 층들에 대해서도 ...

또는 모든 단일 콜백에 대해 명명 된 함수를 선언하지 않고 들여 쓰기 수준을 줄이는 데 도움이되는 프레임 워크 등이 있습니까? 콜백 피라미드는 어떻게 처리합니까?


2
클로저에 대한 추가 문제에 주목하십시오-JS 클로저는 전체 부모 컨텍스트를 캡처합니다 (다른 언어에서는 사용 된 변수 또는 사용자가 특별히 요청한 변수 만 캡처합니다). 콜백 계층 구조가 충분히 깊고 예를 들어 콜백은 어딘가에 유지됩니다.
Eugene

답변:


7

약속은 비동기 동작과 인터페이스 사이의 문제를 명확하게 분리하여 콜백없이 비동기 함수를 호출 할 수 있으며 일반 약속 인터페이스에서 콜백 상호 작용을 수행 할 수 있습니다.

"약속"에는 여러 가지 구현이 있습니다.


예를 들어이 중첩 콜백을 다시 작성할 수 있습니다

http.get(url.parse("http://test.com/"), function(res) {
    console.log(res.statusCode);
    http.get(url.parse(res.headers["location"]), function(res) {
        console.log(res.statusCode);
    });
});

처럼

httpGet(url.parse("http://test.com/")).then(function (res) {
    console.log(res.statusCode);
    return httpGet(url.parse(res.headers["location"]));
}).then(function (res) {
    console.log(res.statusCode);
});

콜백에서 콜백 대신 a(b(c()))".then"을 연결합니다 a().then(b()).then(c()).


소개 : http://howtonode.org/promises


이 자료들이 무엇을하는지 더 자세히 설명해 주시겠습니까? 그리고 질문에 대답 할 때 왜 그 자료들을 추천하십니까? "링크 전용 답변" 은 Stack Exchange에서 환영받지 못합니다
gnat

1
알았어 미안해. 예와 더 많은 정보를 추가했습니다.
Fabien Sa

3

약속의 대안으로 EcmaScript 6에 도입 될 생성기 함수yield 와 함께 키워드를 살펴 봐야합니다 . 둘 다 오늘 Node.js 0.11.x 빌드에서 사용할 수 있지만 Node를 실행할 때 플래그 를 추가로 지정해야합니다. .js :--harmony

$ node --harmony app.js

이러한 구조와 TJ Holowaychuk의 공동 과 같은 라이브러리를 사용하면 비동기 방식으로 실행되지만 동기식 코드처럼 보이는 스타일로 비동기식 코드를 작성할 수 있습니다 . 기본적으로 이러한 것들이 함께 Node.js에 대한 공동 루틴 지원을 구현합니다.

기본적으로 비동기 작업을 실행하는 코드에 대해 생성기 함수를 작성하고 비동기 작업을 호출하지만 yield키워드 앞에 접두사를 추가해야 합니다. 따라서 결국 코드는 다음과 같습니다.

var run = function * () {
  var data = yield doSomethingAsync();
  console.log(data);
};

이 생성기 기능을 실행하려면 앞에서 언급 한 co와 같은 라이브러리가 필요합니다. 그런 다음 전화는 다음과 같습니다.

co(run);

또는 인라인으로 넣으려면 다음을 수행하십시오.

co(function * () {
  // ...
});

제너레이터 함수에서 다른 제너레이터 함수를 호출 할 수 있습니다 yield. 다시 접두사 만 있으면 됩니다.

이 주제에 대한 소개를 보려면 Google에서 검색어와 같은 용어를 검색 yield generators es6 async nodejs하면 수많은 정보를 찾아야합니다. 익숙해지기까지는 시간이 걸리지 만 일단 받으면 다시 돌아가고 싶지 않습니다.

이것은 함수를 호출하는 더 좋은 구문을 제공 할뿐만 아니라 for루프 또는 try/ 와 같은 일반적인 (동기식) 제어 흐름 논리 항목을 사용할 수있게합니다 catch. 많은 콜백과이 모든 것들로 더 이상 혼란스럽지 않습니다.

행운을 빌고 재미있게 보내 :-)!


0

이제 asyncawait 패키지가 있으며 , Node에서 &의 기본 지원 이 무엇인지에 대한 구문과 매우 유사합니다 .awaitasync

기본적으로 비동기식 코드작성 하여 약간의 성능 손실 (패키지 소유자의 숫자는 원시 콜백과 비교하여 79 % 속도 임) 과 함께 LOC 및 들여 쓰기 수준을 크게 줄이면서 기본 지원을 사용할 수있을 때 희망적으로 줄입니다.

성능이 주요 관심사가 아니고 동기식 작성 스타일이 프로젝트 요구에 더 잘 맞는 경우, 악몽 IMO의 콜백 지옥 / 피라미드에서 벗어나는 것이 좋습니다.

패키지 doc의 기본 예 :

var foo = async (function() {
    var resultA = await (firstAsyncCall());
    var resultB = await (secondAsyncCallUsing(resultA));
    var resultC = await (thirdAsyncCallUsing(resultB));
    return doSomethingWith(resultC);
});
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.