2016-01-22 2 views
2

Так что, если у вас есть функция, как это:Могут ли генераторы ES6 передавать данные, обычно передаваемые на обратный вызов/обещание?

function* queryDB(query){ 
    yield db.collection.find(query); 
} 

Из того, что я понимаю, это позволит получить какие db.collection.find() возвращается, так сказать, он возвращает обещание, то queryDB() должен возвращать итератор с обещанием в виде ценность в нем, поэтому что-то вроде co можно использовать для консолидации обещаний, полученных в одно обещание. Есть ли способ дать то, что будет передано этому обещанию, без изменения db.collection.find(), чтобы я мог просто использовать цикл for для цикла по результатам из базы данных?

быть ясным

Я спрашиваю, могу ли я получить аргументы, которые передаются функции перешедшего в .then() обещания. Как и в

queryDB().then(function(<values>) 

но вместо этого я выход итератора из <values>.

+0

[Нет] (http://stackoverflow.com/a/29281361/1048572) – Bergi

+0

'для ... of' синхронно. Синхронно обрабатывать асинхронные методы невозможно. –

+0

... ummm Я не думаю, что вы правильно прочитали мой вопрос ... Я могу * перебрать результат * генератора. –

ответ

1

Вы можете сделать это только внутри генератор.

function* queryDB(query) { 
    // Here is synchrous-like code! 
    var rows = yield db.collection.find(query); 

    var sum = 0; 

    // Use the rows synchrously 
    for (var x of rows) { 
    sum += x; 
    } 

    return sum; 
} 

var sumPromise = doM(queryDB('query example')); 

sumPromise.then(console.log.bind(console)); 

См demo (я рекомендую играть с этим и увидеть, что она возвращается в разных случаях, и это будет понятно).


И вы не можете сделать:

for (var x of db.collection.find(query)) 
    ... 

Или:

for (var x of queryDB('some query')) 
    ... 

Это будет как:

for (var x of (new Promise(...))) 
    ... 

Ваш генератор/обертка будет возвращать a pr omise. Вы можете сделать только then.


И вы не можете сделать:

function* queryDB(query) { 
    db.collection.find(query).then(function(values) { 
     yield values; 
    }); 
} 

Объяснение последнего:

Как компилятор увидит этот код:

function* queryDB(query) { 
    db.collection.find(query).then(anonymousFunction); 
} 

И anonymousFunction я s не является генератором, поэтому вы не можете написать yield. Кроме того, Promise в then не ожидает генератор.

С другой стороны, если вы хотите использовать for (var x in queryDB()), компилятор рассчитывает вернуть массив из queryDB(). Если ваш queryDB() будет асинхронным, он вернет интерфейс, подобный Promise.

При переключении на более функциональный стиль, вы можете написать:

forEach(queryDB(), function(item) { 
    // action on item 
}); 

Вы можете сделать reduce или map реализации, если вам сейчас, что ваше обещанное значение является массивом. Но в этом случае вам не нужен генератор.


doM реализация:

function doM(gen) { 
    function step(value) { 
    var result = gen.next(value); 
    if (result.done) { 
     return result.value; 
    } 
    return result.value.then(step); 
    } 
    return step(); 
} 

Источник: Monads in JavaScript.

forEach реализация:

function forEach(promise, callback) { 
    return promise.then(function(iterable) { 
    for (var x of iterable) { 
     callback(x); 
    } 
    }); 
} 
+1

Именно это и делает OP. Только используя 'co', вместо рукописного' doM'. – Bergi

+0

Да, я спрашиваю, как я могу привести аргументы, переданные в это обещание. –

+0

Отредактированный ответ, не уверен, правильно ли я понял вопрос. Надеюсь, что это издание станет более полезным для объяснения техники. Согласитесь с Берги, что 'for x of queryDB()' невозможно за пределами генератора (обертки). –

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