2014-01-09 3 views
2

제 질문은 약속을 구축하는 함수에 컨텍스트와 인수를 모두 전달해야 할 때 BlueBird에있는 약속의 우아한 병렬화에 관한 것입니다.병렬 약속의 유체 구성

내 문제를 이해하고 테스트 할 수 있도록하기 위해 종속성이없는 예제를 만들었습니다.

비동기 "컴퓨터"(자원을 해제해야 함)가 관련된 계산 (1/(x x x) + 1/(x * x))을 가정 해 봅니다. 사각형과 큐브는 비동기 적으로 독립적으로 계산됩니다.

나는이처럼 내 계산을 수행 할 수 있습니다

InitComputer(2) // returns a promise 
.then(invert) 
.then(function(arg){ 
    return Promise.all([ 
     proto.square(arg), 
     proto.cube(arg) 
    ]); 
}).spread(function(sq, cu){ 
    this.set(sq + cu); 
}).catch(function(err){ 
    console.log('err:', err); 
}).finally(endComputer); 

하지만 이론적으로는 가능 것과 비교 all 너무 무거운의 사용을 찾을 수 있습니다. then에 인수로 함수를 전달하면 실행됩니다. all에 함수를 전달할 때 오류가 발생합니다.

InitComputer(2) 
.then(invert) 
.all([ 
    proto.square, 
    proto.cube 
]).spread(function(sq, cu){ 
    this.set(sq + cu); 
}).catch(function(err){ 
    console.log('err:', err); 
}).finally(endComputer); 

: 나는

이 스타일의 간단한 무언가로 변경하는 솔루션이 있나요 ... 내가 유틸리티 또는 패턴을 누락 의심?

나는 아마도 Promise.prototype.all을 해킹하거나 다형성을 증가시키지 않으려는 새로운 기능을 정의 할 수 있지만 소유하지 않은 객체의 수정과 관련없는 솔루션에만 관심이 있습니다.


부록 :

여기 내 테스트에 대해 "컴퓨터"를 정의하는 방법은 다음과 같습니다 당신이 Promise.all를 사용할 필요가 없습니다

var Promise = require("bluebird"); 

function Computer(){} 
function InitComputer(v){ 
    // initializing a computer is asynchronous and may fail hence the promise 
    var c = new Computer(), resolver = Promise.defer(); 
    setTimeout(function(){ 
     if (v>1) resolver.resolve(v); 
     else resolver.reject(new Error("bad value: "+v)); 
    },100); 
    return resolver.promise.bind(c); 
} 
var proto = Computer.prototype; 
proto.square = function(x){ 
    // imagine this really uses the computer and is asynchronous 
    if (!this instanceof Computer) throw new Error('not a computer'); 
    return x*x 
} 
proto.cube = function(x){ return x*x*x } 
proto.set = function(v){ this.value = v } 

function endComputer(){ 
    // releases resources here 
    console.log('value:', this.value); 
} 

// this asynchronous function doesn't involve or know the computer 
function invert(v){ return 1/v } 
+0

뭔가 잘못을 받고 있지만, 때로 믿을 수 있습니다 'proto.square (arg)'와'proto.cube (arg)'는 즉시 평가되고, 결과는'Promise.all'에 대한 배열 생성자로 전달됩니까? (편집) 오, 오케이, 그들은 아마 비동기, 결코 마음이 있어야합니다. – Groo

+0

@ 그 라우 바로. * "실제로 컴퓨터를 사용하고 비동기식이라고 상상해보십시오"*. 질문을 읽을 수 있도록 최소한의 코드를 만들었으므로 몇 가지 바로 가기를 사용해야했습니다. –

답변

3

. 대신 일을 :

.then(function(arg){ 
    return Promise.all([ 
     proto.square(arg), 
     proto.cube(arg) 
    ]); 
}).spread(... 

당신은 간단하게 사용할 수 있습니다

.then(function(arg){ 
    return [proto.square(arg), proto.cube(arg)]; 
}).spread(... 

우리는 Node.js를에 화살표 기능이 있다면,처럼 간단 할 것 :

.then(arg => [proto.square(arg), proto.cube(arg)]).spread(... 

Promise.all입니다 적어도 2 약속을 약속의 체인을 시작해야 할 때 사용됩니다. 예를 들면 : 당신이 언급하는 것처럼 자원의 관리를 위해

var promise1 = somePromise(); 
var promise2 = somePromise2(); 

// Start the chain here 
Promise.all([promise1, promise2]) 
.spread(function(value1, value2) { 
    // ... 
}); 
+0

희망만큼 간단하지는 않지만 실제로 받아 들일 수 있습니다. –

+1

나는 왜'all'은'then'과는 반대로 인수에서 함수를 실행하지 않는지 궁금합니다. –

+0

@dystroy 하, 그것은 주로'this.square'와'this.cube'를 사용하는 것이 었습니다. –

1

이 케이스를 사용, 블루 버드는 Promise.using()있다.Promise.using() 당신이 cubesquare 비동기 방식

여기

나는 약간 InitComputer을 쓴 다시의 결과를 결합 할뿐만 아니라 도움이 될

Promise.join()를 사용하여 수행 할 때 자동으로 비동기-검색 자원을 닫는 당신에게 설치 disposer() 기능을 할 수 있습니다 예제가 어떻게 작동하는지 보여주기 위해 - 이제는 val 대신 속성으로 val이 추가 된 Computer 인스턴스를 반환하고 프로토 타입에 endComputer을 배치했습니다.

참고 : 항상를 사용할 수 있습니다. 그래서 반환하는 대신 같은지연된 :

var invert = Promise.method(function invert(v){ return 1/v })

새로운 initComputer :

function InitComputer(v){ 
    var c = new Computer(), resolver = Promise.defer(); 
    setTimeout(function(){ 
     if (v>1) { 
      c.val = v; 
      resolver.resolve(c); 
     } 
     else resolver.reject(new Error("bad value: "+v)); 
    },100); /** notice resource disposer function added below **/ 
    return resolver.promise.bind(c).disposer(function(compu){compu.endComputer()}); 
} 

새로운 코드 :

Promise.using(InitComputer(1.2), function(computer){ 
    return invert(computer.val) 
    .then(function(inverted){ 
     return Promise.join(computer.square(inverted), computer.cube(inverted), 
      function(sq, cu){ 
       computer.set(sq + cu) 
      } 
     ) 
    }) 
    .catch(function(err){ 
     console.log('err:', err); 
    }); 
}) 
+0

+1하지만 물어볼 때 사용할 수 없었던 기능 (예 :'Promise.using')으로 이미 답을 얻은 오래된 질문에 답하고 있습니다. 이 오래된 질문을 되살리는 것은 약간 지저분합니다. 'Promise.defer()'는 더 단순한'새로운 약속 (f1, f2)'을 선호하기 때문에 BlueBird의 저자에 의해 반 패턴으로 선언되었습니다. –

+0

늦게 들어 와서 네 고마워하지만 이것은 내 검색에서 1 위로 올라와서 광고가 $ 0.02라고 생각했습니다 .. 나는 또한 [여기] 대답을 찾았습니다 (http://stackoverflow.com/questions/24615891/best-practice-to-hang- on-to-variables-when-using-promises)이 주제에서 많은 도움이된다. – aarosil