Уступая от обратного вызова итератора, используемого внутри генератора

Кто-нибудь пытался получить Underscore JS или lodash (или любые стандартные функции ES5 в этом случае), работающие с генераторами?

Если у нас есть массив var myArray = [1,2,3,4,6]; Мы хотим, чтобы он прошел через него.

В случае с негенератором вы просто

myArray.forEach(function(k) {
  console.log(k);
});

Однако, когда вы не можете уступить внутри функции негенератора, поэтому, если внутри этого цикла нам нужно выполнить некоторую работу async, вам нужно будет сделать следующее.

var foreach = function* (arr, fn) {
  var i;
  for (i = 0; i < arr.length; i++) {
    yield * fn(arr[i], i);
  }
};

yield* foreach(myArray, function* (k) {
  var a = yield fs.readFile();
});

Какой вид отстой.

Кто-нибудь знает, как получить анонимные функции, работающие с генераторами? Из-за этого мы теряем всю библиотеку lodash.

Примечание. Я использую Traceur для компиляции моего кода в ES6 с включенными генераторами.
Примечание. Я не использую co(). Я использую пользовательскую функцию генератора, которая видна ниже

var run = function(generatorFunction) {
  var generatorItr = generatorFunction(resume);
  function resume(callbackValue) {
    generatorItr.next(callbackValue);
  }
  generatorItr.next();
};

Ответ 1

Если я правильно понимаю вашу проблему, по существу, вы пытаетесь что-то сделать (итерацию до тех пор, пока не будет найдена хорошая точка остановки) асинхронным способом на языке (JS), который действительно разработан вокруг синхронности. Другими словами, хотя вы обычно можете:

_([1,2,3]).any(function(x) {
    var shouldWeStopLooping = x % 2 == 0;
    return shouldWeStopLogging;
});

вместо этого вы хотите заставить "прекратить цикл" перерыв кода из нормального выполнения, а затем вернуться, что невозможно при использовании традиционного JS (yield относительно новое для языка) и, следовательно, не возможно в Underscore/Lodash:

_([1,2,3]).any(function(x) {
    var shouldWeStopLooping = $.ajax(...); // Doesn't work; code keeps going
    return shouldWeStopLogging;
});

Есть два подхода, которые вы могли бы предпринять, ни один из них не идеален.

Как уже упоминалось в комментариях, одним из способов было бы сделать всю вашу "отложенную" работу сначала, а затем повторить:

var workInProgress = _([1,2,3]).map(someAjaxOperation);
$.when.apply(workInProgress).done(doSomethingBasedOnAjaxResults);

Но (как также отмечено в комментариях), это не совсем то же самое, что и вы делаете работу AJAX во всех элементах вашего массива (по сравнению с истинным генератором, который будет только перебирать столько, сколько необходимо найти "победителя" ).

Другим подходом было бы исключить асинхронность. jQuery позволяет передать async: false запрос AJAX, который "решает" проблему, разрешив вам использовать Underscore/Lodash/whatever..., но также блокирует ваш пользовательский браузер до тех пор, пока требуется выполнение работы AJAX, что, вероятно, не то, что вы хотите.

К сожалению, если вы хотите использовать библиотеку, такую ​​как Underscore/Lodash, это единственные варианты, которые я вижу. Единственным другим вариантом было бы написать собственный микшер Underscore/Lodash, что действительно не так сложно. Я бы рекомендовал это сделать, так как это позволит вам все еще использовать все другие замечательные функции в этих библиотеках, сохраняя при этом последовательный путь.