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

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

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



답변

구식 속임수는 작업에 적합한 도구를 선택해야한다는 것입니다. 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
});


답변