Как я могу выполнять операции в javascript так же, как мы выполняем конвейер операций в потоках java?

В Java 8 с использованием потоков, когда я цепочечные методы один за другим, выполнение операций выполняется конвейерным способом. Пример: -

List<Integer> nums = Arrays.asList(1,2,3,4,5,6);    
nums.stream().map(x->{
    x = x * x;
    System.out.println("map1="+x);
    return x;
}).map(x->{
    x = x * 3;
    System.out.println("map2="+x);
    return x;
}).forEach(x-> System.out.println("forEach="+x));

Выход:-

map1=1
map2=3
forEach=3
map1=4
map2=12
forEach=12
map1=9
map2=27
forEach=27
map1=16
map2=48
forEach=48
map1=25
map2=75
forEach=75
map1=36
map2=108
forEach=108

Но когда я попытался аналогичным образом в javascript. Результат другой. Как и в javascript, первая операция завершается, а затем выполняется вторая операция. Пример: -

var nums = [1,2,3,4,5,6 ];
nums.map(x => {
  x = (x * x);
  console.log('map1='+x);
  return x;})
  .map(x => {
  x = x * 3;
  console.log('map2='+x);
  return x;})
  .forEach(x=> console.log('forEach='+x));

Выход:-

 map1=1
 map1=4
 map1=9
 map1=16
 map1=25
 map1=36
 map2=3
 map2=12
 map2=27
 map2=48
 map2=75
 map2=108
 forEach=3
 forEach=12
 forEach=27
 forEach=48
 forEach=75
 forEach=108

Есть ли способ в javascript, что он выполняет операции в конвейерном режиме, и я получаю вывод в виде Java-программы?

Этот вопрос задают только как собрать как в javascript, а не как внутренние рабочие изменения для методов того же типа

Ответ 1

Возможно позже (или никогда) вы можете использовать фактический экспериментальный оператор конвейера |>, который имеет следующий синтаксис:

expression |> function

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

Это работает только в FF. Начиная с версии 58: эта функция находится за флагом компиляции --enable-pipeline-operator.

const
    a = x => { x = x * x; console.log("map1=" + x); return x; },
    b = x => { x = x * 3; console.log("map2=" + x); return x; },
    c = x => console.log("forEach=" + x)

var nums = [1, 2, 3, 4, 5, 6];

nums.forEach(v => v |> a |> b |> c);

Ответ 2

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

var nums = [1,2,3,4,5,6 ];
var fns = [
  (x) => {
    x = x * x;
    console.log('map1=' + x);
    return x;
  },
  (x) => {
    x *= 3;
    console.log('map2=' + x);
    return x;
  },
  (x) => {
    console.log(x);
    return x;
  }
];

nums.forEach((num) => {
  fns.reduce((lastResult, fn) => fn(lastResult), num);
  // pass "num" as the initial value for "lastResult",
  // before the first function has been called
});

Ответ 3

Зачем заново изобретать, когда у нас есть решения. Эта функциональность присутствует в lodash/RxJS/stream.js.

Пример фрагмента из lodash:

_.flow(
 _.assign(rows[0]),
 _.omit('blah')
)(foundUser);

// >> {"charData":[],"ok": 1}

Тем не менее, JavaScript работает на одном потоке, как и эти библиотеки. Потоки Java получают выгоду от многоядерных систем (в случае параллельной работы). Там они могут использовать несколько потоков, чтобы использовать все доступные ядра.

Ответ 4

Вы получаете тот же вывод, что и относительные значения последовательности map1, map2 и forEach.

Разница в порядке, который вы видите, показывает основное различие между моделями машин JVM и движком JavaScript.

JVM имеют резьбу. JavaScript нет. Это означает, что ваши шаги последовательности в Java могут выполняться сразу после того, как произошло критическое число операций с картой.

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

Как видите, методы функционально эквивалентны, но имеют разную механику.

Ответ 5

Отображение javascrip не использует несколько потоков, поэтому вы получите вывод, где каждый этап выполняется последовательно.

Чтобы получить то же поведение, что и в Java, я бы предложил использовать библиотеки, такие как RxJS. Это дает вам больше контроля над типом обработки, будь то последовательная, параллельная или какая-либо еще.

Вот пример, который близок к тому, что вы ожидаете:

const source = Rx.Observable.from([{name: 'Joe', age: 30}, {name: 'Frank', age: 20},{name: 'Ryan', age: 50}]);
const example = source.map(person => {
  console.log("Mapping1" + person.name)
  return person.name
});
const subscribe = example.subscribe(val => console.log(val));

выходы:

"Mapping1Joe"
"Joe"
"Mapping1Frank"
"Frank"
"Mapping1Ryan"
"Ryan"