ES6 약속이 있으므로 Q 또는 BlueBird와 같은 약속 라이브러리를 사용해야 할 이유가 있습니까? [닫은]


228

Node.js가 약속에 대한 기본 지원을 추가 한 후에도 Q 또는 BlueBird와 같은 라이브러리를 사용해야하는 이유가 있습니까?

예를 들어, 새 프로젝트를 시작하고이 프로젝트에서 이러한 라이브러리를 사용하는 종속성이 없다고 가정하면 해당 라이브러리를 사용할 이유가 더 이상 없다고 말할 수 있습니까?


4
기본 약속에는 매우 기본적인 기능이 있습니다. Q 또는 Bluebird와 같은 라이브러리는 더 많은 것을 추가합니다. 해당 기능이 필요한 경우 해당 라이브러리를 사용하십시오.
gman

7
제목을 편집하여 "필요"에 대한 정보를 줄이고 "약속 라이브러리를 사용해야하는 이유"에 대해 자세히 설명했습니다. 이 질문은 의견이 아니라 사실을 제공함으로써 대답 할 수 있습니다. 주로 의견이 아닌 사실을 제공하여 답변을 얻을 수 있기 때문에 다시 열어야합니다. 그것을 보여주는 데모로 아래 답변을 참조하십시오.
jfriend00

11
@JaromandaX-제목과 질문이 약속 라이브러리를 사용하기 위해 "필요"여부보다는 약속 라이브러리를 사용하는 이유에 대해 더 많이 조정되었으므로 다시 열어야합니다. 내 의견으로는,이 질문은 주로 의견이 아닌 사실을 제공함으로써 대답 할 수 있습니다-아래 답변을 데모로보십시오.
jfriend00

6
제목 편집 후의이 질문과 그 대답은 의견에 근거한 것이 아닙니다.
최대

7
동의했다. 이것은 현재 형태로 완벽하게 유효한 질문입니다. 재 개설 후보로 지명되었습니다.
Jules

답변:


367

구식 속임수는 작업에 적합한 도구를 선택해야한다는 것입니다. ES6 약속은 기본을 제공합니다. 당신이 원하거나 필요로하는 모든 것이 기본이라면, 그것은 당신에게 잘 작동 할 것입니다. 그러나 도구 상자에는 기본 사항보다 더 많은 도구가 있으며 이러한 추가 도구가 매우 유용한 상황이 있습니다. 그리고 ES6 약속에는 거의 모든 node.js 프로젝트에 유용한 약속과 같은 몇 가지 기본 사항이 누락되어 있다고 주장합니다.

저는 Bluebird promise 라이브러리에 가장 익숙 하므로 대부분 해당 라이브러리에 대한 경험을 통해 이야기하겠습니다.

보다 유능한 Promise 라이브러리를 사용해야하는 6 가지 이유는 다음과 같습니다.

  1. 인터페이스 비동기 비 Promisified - .promisify()그리고 .promisifyAll()한 줄의 코드는 전체 인터페이스의 promisified 버전을 생성 - 여전히 일반 콜백을 필요로하고 아직 약속을 반환하지 않는 모든 비동기 인터페이스를 처리 할 수 매우 유용합니다.

  2. 빠름 -Bluebird는 대부분의 환경에서 기본 약속보다 훨씬 빠릅니다 .

  3. 비동기 배열 반복 시퀀싱 - Promise.mapSeries()또는 Promise.reduce()각 요소에 대해 비동기 작업을 호출하는 동시에 배열을 반복 할 수 있지만 비동기 작업을 시퀀싱하여 동시에 수행되는 것은 아닙니다. 대상 서버에 필요하거나 하나의 결과를 다음 서버로 전달해야하기 때문에이 작업을 수행 할 수 있습니다.

  4. Polyfill- 구 버전의 브라우저 클라이언트에서 약속을 사용하려면 어쨌든 polyfill이 필요합니다. 유능한 폴리 필을 얻을 수도 있습니다. node.js에는 ES6 약속이 있으므로 node.js에는 폴리 필이 필요하지 않지만 브라우저에는있을 수 있습니다. node.js 서버와 클라이언트를 모두 코딩하는 경우 동일한 약속 라이브러리와 기능을 둘 다 (코드 공유, 환경 간 컨텍스트 전환, 비동기 코드에 공통 코딩 기술 사용 등)에 매우 유용 할 수 있습니다. ).

  5. 기타 유용한 기능 - 파랑새는있다 Promise.map(), Promise.some(), Promise.any(), Promise.filter(), Promise.each()Promise.props()모든 때때로 편리합니다. 이러한 작업은 ES6 약속 및 추가 코드를 사용하여 수행 할 수 있지만 Bluebird는 이러한 작업이 이미 사전 빌드 및 사전 테스트되었으므로이를 사용하는 것이 더 간단하고 적은 코드입니다.

  6. 기본 제공 경고 및 전체 스택 추적 -Bluebird에는 잘못된 코드 나 버그 일 수있는 문제를 경고하는 여러 가지 기본 제공 경고가 있습니다. 예를 들어, .then()해당 약속을 반환하지 않고 처리기 내에 새로운 약속을 만드는 함수를 호출하면 (현재 약속 체인에 연결하기 위해) 대부분의 경우 이는 우발적 인 버그이며 Bluebird는 경고를 표시합니다. 효과. 다른 내장 블루 버드 경고는 여기설명되어 있습니다 .

이러한 다양한 주제에 대한 자세한 내용은 다음과 같습니다.

약속하다

node.js 프로젝트에서는 .promisifyAll()모듈과 같은 표준 node.js 모듈을 많이 사용하기 때문에 모든 곳에서 Bluebird를 즉시 사용 fs합니다.

Node.js 자체는 fs 모듈 과 같은 비동기 IO를 수행하는 내장 모듈에 대한 약속 인터페이스를 제공하지 않습니다 . 따라서 해당 인터페이스와 함께 약속을 사용하려면 사용하는 각 모듈 함수 주위에 약속 래퍼를 직접 코딩하거나 약속을 사용하지 않거나 사용할 수있는 라이브러리를 가져와야합니다.

블루 버드의 Promise.promisify()Promise.promisifyAll()약속을 반환 컨벤션 비동기 API를 호출 Node.js를의 자동 포장을 제공한다. 매우 유용하고 시간을 절약 할 수 있습니다. 나는 항상 그것을 사용합니다.

작동 방식의 예는 다음과 같습니다.

const Promise = require('bluebird');
const fs = Promise.promisifyAll(require('fs'));

fs.readFileAsync('somefile.text').then(function(data) {
   // do something with data here
});

대안은 fs사용하려는 각 API 에 대해 자체 약속 래퍼를 수동으로 만드는 것입니다 .

const fs = require('fs');

function readFileAsync(file, options) {
    return new Promise(function(resolve, reject) {
        fs.readFile(file, options, function(err, data) {
            if (err) {
                reject(err);
            } else {
                 resolve(data);
            }
        });
    });
}

readFileAsync('somefile.text').then(function(data) {
   // do something with data here
});

또한 사용하려는 각 API 함수에 대해 수동으로이 작업을 수행해야합니다. 이것은 분명히 이해가되지 않습니다. 상용구 코드입니다. 이 작업을 수행하는 유틸리티를 얻을 수도 있습니다. 블루 버드 Promise.promisify()Promise.promisifyAll()같은 유틸리티입니다.

다른 유용한 기능

다음은 특히 유용한 Bluebird 기능 중 일부입니다 (코드를 저장하거나 개발 속도를 높일 수있는 방법에 대한 몇 가지 코드 예제가 있음).

Promise.promisify()
Promise.promisifyAll()
Promise.map()
Promise.reduce()
Promise.mapSeries()
Promise.delay()

유용한 기능 외에도 Promise.map()동시에 실행할 수있는 작업 수를 지정할 수있는 동시성 옵션도 지원 합니다.이 기능 은 할 일이 많을 때 특히 유용하지만 외부를 압도 할 수없는 경우에 특히 유용합니다. 자원.

이들 중 일부는 독립형이라고 할 수 있으며 많은 코드를 절약 할 수있는 iterable로 해결된다는 약속에 사용될 수 있습니다.


폴리 필

브라우저 프로젝트에서는 일반적으로 Promise를 지원하지 않는 일부 브라우저를 계속 지원하고자하므로 결국에는 폴리 필이 필요합니다. jQuery를 사용하는 경우 jQuery에 내장 된 약속 지원을 사용할 수도 있습니다 (jQuery 3.0에서 수정 된 방식으로 고통 스럽지만 비표준 임에도 불구하고). 프로젝트에 중요한 비동기 활동이 포함되어 있다면 블루 버드의 확장 기능은 매우 유용합니다.


빨리

또한 Bluebird의 약속은 V8에 제공된 약속보다 훨씬 빠르다는 점에 주목할 가치가 있습니다. 해당 주제에 대한 자세한 내용은 이 게시물 을 참조하십시오 .


큰 일 Node.js가 누락되었습니다

node.js 개발에서 Bluebird를 덜 사용하는 것을 고려하게 만드는 것은 node.js가 약속 함수에 내장되어 있으면 다음과 같이 할 수 있습니다.

const fs = requirep('fs');

fs.readFileAsync('somefile.text').then(function(data) {
   // do something with data here
});

또는 내장 모듈의 일부로 이미 약속 된 방법을 제공하십시오.

그때까지, 나는 이것을 Bluebird와 함께합니다 :

const Promise = require('bluebird');
const fs = Promise.promisifyAll(require('fs'));

fs.readFileAsync('somefile.text').then(function(data) {
   // do something with data here
});

ES6 promise 지원이 node.js에 내장되어 있고 내장 모듈 중 어느 것도 약속을 반환하지 않는 것이 약간 이상합니다. 이것은 node.js에서 정렬해야합니다. 그때까지 나는 Bluebird를 사용하여 전체 라이브러리를 약속합니다. 따라서 내장 모듈 중 어느 것도 먼저 약속을 수동으로 감싸지 않고 약속을 사용할 수 없으므로 node.js에서 약속이 약 20 % 구현 된 것처럼 느껴집니다.


다음은 일반 약속과 블루 버드의 약속과 Promise.map()파일 세트를 동시에 읽고 모든 데이터를 다룰 때 알리는 예입니다.

일반 약속

const files = ["file1.txt", "fileA.txt", "fileB.txt"];
const fs = require('fs');

// make promise version of fs.readFile()
function fsReadFileP(file, options) {
    return new Promise(function(resolve, reject) {
        fs.readFile(file, options, function(err, data) {
            if (err) return reject(err);
            resolve(data);
        });
    });
}


Promise.all(files.map(fsReadFileP)).then(function(results) {
    // files data in results Array
}, function(err) {
    // error here
});

블루 버드 Promise.map()Promise.promisifyAll()

const Promise = require('bluebird');
const fs = Promise.promisifyAll(require('fs'));
const files = ["file1.txt", "fileA.txt", "fileB.txt"];

Promise.map(files, fs.readFileAsync).then(function(results) {
    // files data in results Array
}, function(err) {
    // error here
});

다음은 일반 약속과 블루 버드의 약속의 예이며 Promise.map()원격 호스트에서 한 번에 최대 4 개까지 읽을 수 있지만 허용되는 한 많은 요청을 병렬로 유지하려는 URL을 읽을 때 다음과 같습니다.

평범한 JS 약속

const request = require('request');
const urls = [url1, url2, url3, url4, url5, ....];

// make promisified version of request.get()
function requestGetP(url) {
    return new Promise(function(resolve, reject) {
        request.get(url, function(err, data) {
            if (err) return reject(err);
            resolve(data);
        });
    });
}

function getURLs(urlArray, concurrentLimit) {
    var numInFlight = 0;
    var index = 0;
    var results = new Array(urlArray.length);
    return new Promise(function(resolve, reject) {
        function next() {
            // load more until concurrentLimit is reached or until we got to the last one
            while (numInFlight < concurrentLimit && index < urlArray.length) {
                (function(i) {
                    requestGetP(urlArray[index++]).then(function(data) {
                        --numInFlight;
                        results[i] = data;
                        next();
                    }, function(err) {
                        reject(err);
                    });
                    ++numInFlight;
                })(index);
            }
            // since we always call next() upon completion of a request, we can test here
            // to see if there was nothing left to do or finish
            if (numInFlight === 0 && index === urlArray.length) {
                resolve(results);
            }
        }
        next();
    });
}

블루 버드 약속

const Promise = require('bluebird');
const request = Promise.promisifyAll(require('request'));
const urls = [url1, url2, url3, url4, url5, ....];

Promise.map(urls, request.getAsync, {concurrency: 4}).then(function(results) {
    // urls fetched in order in results Array
}, function(err) {
    // error here
});

그것은 어떤면에서 고통스럽게 비표준 비록 - - 그들은 "약속 / A + 호환"지금 :)이라고 주장 blog.jquery.com/2016/01/14/jquery-3-0-beta-released
thefourtheye

1
@thefourtheye-예, 그들이 3.0에서 Promise / A + 호환성을 위해 노력하고 있음을 알고 있습니다. 그러나 아직 베타 버전입니다. 그것이 약속을 지키는 경우 (펀칭 의도), 이미 jQuery를 사용하고 있다면 브라우저 JS에서 외부 약속 라이브러리를 사용해야하는 이유를 제거 할 수 있습니다. 여전히 Bluebird가 제공하는 유용한 기능을 모두 갖추고 있지는 않으며 Bluebird의 성능에 부응하면 놀라 울 것입니다. 어쨌든 OP의 질문은 주로 node.js에 관한 것 같습니다.
jfriend00

1
마지막 예제 코드에는 약간의 오타가 return new Promise(function(resolve, rejct)있습니다. 해야합니다reject
세바스찬 Muszyński

7
Node.js는 실제로는 util.promisify있지만 직접적으로 promisifyAll동등한 것은 없습니다 .
nyuszika7h

1
@Aurast-예, v11은을 처리 fs하지만 Bluebird (내가 가장 좋아하는 concurrency옵션 은 옵션입니다 Promise.map())를 사용하여 병렬 요청을 해야하는 대상 서비스를 압도하지 않도록 하는 다른 이유가 있습니다 . 또한 블루 버드의 promisifyAll과 함께 사용할 다른 많은 약속되지 않은 인터페이스도 있습니다. 그러나 node.js 자체가 기본 제공 약속 지원을 강화함에 따라 모든 새 프로젝트에서 Bluebird를 즉시 확보해야하는 이유는 서서히 사라지고 있습니다.
jfriend00
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.