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 или определить новую функцию, чтобы избежать увеличения полиморфизма, но меня интересуют только решения, не связанные с модификацией объектов, которые у меня нет.


Приложение:

Вот как определил "компьютер" для моего теста:

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

Я мог бы получить что-то неправильно, но Арен 't 'proto.square (arg)' и 'proto.cube (arg)' оцениваются немедленно, прежде чем передать их результаты для конструктора массива для 'Promise.all'? (отредактируйте) о, хорошо, они, вероятно, должны быть асинхронными, неважно. – Groo

+0

@Groo Точно. * «Представьте, что это действительно использует компьютер и является асинхронным» *. Я сделал минимальный код, чтобы дать возможность читать вопрос, поэтому мне пришлось взять несколько ярлыков. –

ответ

3

Вы не должны использовать Promise.all там. Вместо того чтобы делать:

.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 является для использования, когда вам нужно start цепочка обещаний с минимум двумя обещаниями. Например:

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

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

Это не так просто, как я надеялся, но это действительно приемлемо. –

+1

Интересно, почему 'all', вопреки' then', не выполняет функции в аргументе. –

+0

@ dystroy hah, в основном это было использование 'this.square' и' this.cube'. –

1

Для управления ресурсами использовать случай, как вы упоминаете, Блюберд имеет Promise.using().Promise.using() позволяет вам настроить disposer() функции автоматического закрытия асинхронно-извлеченный ресурса, когда вы сделали с помощью

Promise.join() поможет, а объединить результаты методов cube и square асинхронных

Здесь я немного переписал свой InitComputer пример, чтобы проиллюстрировать, как это работает - теперь он возвращает Computer экземпляр с Валу добавляемые как свойство, вместо Валу, и я поставил endComputer на прото также

примечание: вы всегда можете использовать Promise.method() как и вместо возвращения отложенное:

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()' теперь объявляется автором BlueBird как антипаттерн, поскольку он предпочитает более простое «новое обещание (f1, f2)». –

+0

Спасибо, что пришел поздно, но это пришло в первый раз в моем поиске, так что я сделал бы объявление $ 0,02. Я также нашел ответ [здесь] (http://stackoverflow.com/questions/24615891/best-practice-to-hang- on-to-variables-when-use-promises), которые очень полезны в этой теме также – aarosil

 Смежные вопросы

  • Нет связанных вопросов^_^