2016-06-17 4 views
0

Я стараюсь как можно больше упростить цепочки Promise, имея функцию дескриптор массива функций. Они должны быть в порядке, но мой метод дать им правильный синтаксис не работает, и я уверен, что есть лучший способ сделать это. Каждая функция в цепочке вызывает базу данных и должна запускать следующую функцию при ее возврате.Упрощение цепочки обещаний

// Run each in order. 
var Chain = function(chain, cb){ 
    chain.forEach(function(i){ i = function(r){return new Promise(i)}; }); 
    chain.reduce(function(cur, next) { {cur.then(next)} }, Promise.resolve()).then(function() { cb() }); 
} 
Chain([ 

    r=>{ 
     UserData('elle', i=>{ 
      console.log(i); 
      r(i) 
     }) 
    }, 
    r=>{ 
     UserData('tyler', {age:"22"}, i=>{ 
      console.log(i); 
      r(i); 
     }) 
    }, 
    r=>{ 
     UserData('nerd', i=>{ 
      console.log(i); 
      r(i) 
     }) 
    }, 
    r=>{ 
     UserData('jeax', i=>{ 
      console.log(i); 
      r(i) 
     }) 
    } 

], function(){ 

    console.log("Done."); 

}); 

В приведенном ниже примере работает, как мне это нужно, просто не используя функцию цепи, что я хочу с простотой каждого пункта.

var PChain = function(cb){ 
    // Convert each item. 
    return function(){ return new Promise(r=>{cb(r)}) }; 
} 
// The items. 
var chain = [ 
    PChain(r=>{ 
     UserData('elle', i=>{ 
      console.log(i);r(i) 
     }) 
    }), 
    PChain(r=>{ 
     UserData('tyler', {age:"22"}, i=>{ 
      console.log(i);r(i); 
     }) 
    }), 
    PChain(r=>{ 
     UserData('nerd', 
      i=>{ console.log(i);r(i) 
     }) 
    }), 
    PChain(r=>{ 
     UserData('jeax', 
      i=>{ console.log(i);r(i) 
     }) 
    }) 
]; 
chain.reduce(function(cur, next) { return cur.then(next) }, Promise.resolve()).then(function() { 
    //all executed 
    console.log("Done."); 
}); 
+1

'UserData' кажется странным: он не возвращает обещаний и не придерживается обычного соглашения об обратном вызове аргументов' (err, result) '. – robertklep

+0

Хотя я получаю много насмешек за это, я использую e в качестве второго аргумента. В этом случае я не использовал его, потому что я просто проверяю вещи. UserData использует MongoDB для возврата информации профиля. –

+0

Из приведенного выше кода неясно, почему его нельзя обрабатывать параллельно, но давайте предположим, что это не должно быть. Я считаю, что Bluebird может предложить что-то, что вам нужно, ['mapSeries'] (http://bluebirdjs.com/docs/api/promise.mapseries.html) последовательно обрабатывает массив обещаний. Вышеприведенный код излишне усложнен, я не могу предложить, как это применимо здесь. – estus

ответ

2

Ваша ошибка состоит в Chain функции:

chain.forEach(function(i){ i = function(r){return new Promise(i)}; }); 
chain.reduce(function(cur, next) { {cur.then(next)} }, Promise.resolve()).then(function() { cb() }); 

В частности, присвоение i внутри forEach абсолютно ничего не значит. То, что вы на самом деле хотите, чтобы использовать map:

chain.map(function(exec){ return function(r){ return new Promise(exec)}; }).reduce(…); 

где map возвращает массив функций, которые вы затем можете уменьшить более.


Независимо от того, что вы на самом деле нужно сделать, это promisifyUserData функция:

function user(name, options) { 
    return new Promise((resolve, reject) => { 
     if (options) 
      UserData(name, options, resolve); 
     else 
      UserData(name, resolve); 
    }); 
} 

, с которым вы даже не нужна цепь, но может просто написать

user('elle').then(i => { 
    console.log(i); 
    return user('tyler', {age:"22"}); 
}).then(i => { 
    console.log(i); 
    return user('nerd'); 
}).then(i => { 
    console.log(i); 
    return user('jeax'); 
}).then(i => { 
    console.log(i); 
}).then(function() { 
    //all executed 
    console.log("Done."); 
}); 

Вы все еще можете использовать reduce, если у вас есть массив имен пользователей с динамическим размером, но вы не должны использовать массив функций.

+0

Большое вам спасибо! Это намного лучшая альтернатива и именно то, что я искал :-) +1 за то, что я не обращался к какой-то библиотеке. –

1

Вы должны использовать :

Promise.all([r1, r2, r3]).then(function(values) { 
    // Do something 
}); 

UPDATE

уважать определенный порядок, вы должны check this answer. К сожалению, нет способа ES6, способного сделать это изначально.

Одна из наиболее используемых систем очередей JS-обещаний (среди прочих, by Angular) - это Крис Коваль Q, и это recommend something similar, так что это не так далеко от того, что вы написали.

ПРИМЕЧАНИЕ

В вашем коде, это, кажется, что вы пытаетесь достичь какой-то пакетных запросов. Вы должны знать, что действительно очень мало действительно нужна упорядоченная цепочка обещаний в JS.

  1. Если вы используете это для паров (например, операций с содержимым файлов), лучше использовать pipes.
  2. Если вы используете что для пакетного/отфильтрованных запросов API:
    • Если вы контролируете API: изменить API для управления пакетными/отфильтрованных запросов
    • Если вы не контролируете его: создать средний -ware приложение управления ею
+2

'Они должны быть в порядке' – nils

+0

Я отредактировал свой ответ, чтобы дать более конкретное объяснение. –

+0

Не казаться грубым, но это не ответ, это предположение, что я не занимаюсь практикой. Я один из тех парней, которые считают, что язык позволяет мне это делать, это прекрасно. Я хочу, чего хочу. Двигаясь дальше, все запускает их все сразу, а не в порядке. Вот почему я пытаюсь изменить каждую функцию в цепочке с помощью инструкции forEach, чтобы правильно их связать. Я создал функцию под названием PChain, которая делает почти то же самое и работает, я обновлю свой вопрос, чтобы предоставить ее. –

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