JS Callbacks: продолжение или стиль конфетной фабрики? - PullRequest
0 голосов
/ 24 сентября 2018

На курсе по стилю программирования нас просят реализовать некоторый код как " стиль передачи продолжения " и " стиль фабрики конфет ".

Книга, которую мы читаем, - "Упражнения в стилях программирования" Кристины Видейры Лопес (главы 5 и 8).

Нас просят реализовать примеры кодов книги на другом языке (в книге на языке Python, теперь я использую Javascript).

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

CandyФабричный стиль

#!/usr/bin/env python
read_file(path_to_file):
    """
    Takes a path to a file and returns the entire contents of the 
    file as a string
    """
    with open(path_to_file) as f:
        data = f.read()  
   return data


def filter_chars_and_normalize(str_data):
     ...

.
.
.

print_all(sort(frequencies(remove_stop_words(scan(
filter_chars_and_normalize(read_file(sys.argv[1]))))))[0:25])

Стиль продолжения-прохождения

#!/usr/bin/env python

def read_file(path_to_file, func): 
    with open(path_to_file) as f:
       data = f.read()
    func(data, normalize)


def filter_chars(str_data, func):
    pattern = re.compile(’[\W_]+’)
    func(pattern.sub(’ ’, str_data), scan)


. 
. 
. 


read_file(sys.argv[1], filter_chars)

Javascript

const fs = require('fs');


var myArgs = process.argv.slice(2);

function read_file(path_to_file,callback){
    fs.readFile(path_to_file, "utf-8",(err, data) => {
        if (err) throw err;
        callback(data);
      });
}

function string_to_lower(str_data,callback){
    var data = str_data.toLowerCase()
    callback(data)
}

.
.
.

function TermFrequency(){
    read_file(myArgs[0],function(result){
        string_to_lower(result, function(result2){
            remove_non_alphanumeric(result2,function(result3){
                remove_stop_words(result3,function(result4){
                    frequencies(result4,function(result5,result6){
                            sort(result5,result6,function(result7,result8){
                            write_out(result7,result8)
                        })
                    })
                })
            })
        })
    })
}

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

Как можно добиться стиля кондитерской фабрики, учитывая код, написанный на JSвыше?Это код (который основан на обратных вызовах) конфетной фабрики или стиль прохождения продолжения?Как я могу написать код выше, не используя обратные вызовы и в то же время доверяя JS?

1 Ответ

0 голосов
/ 24 сентября 2018

Я думаю, что вы путаете 2 вещи.Стиль Candy чаще называют функциональной композицией.Вот где выходные данные одной функции являются входными данными для следующей.

f(g(h(1)))

h(1) выводит значение, и это вход для g, который выводит значение и является входом для f.

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

f(1,g)

Где f принимает значение, обрабатывает его и вызывает g позднее.

Часто в JavaScript вам нужно обрабатывать асинхронные операции, но в таких ситуациях вам нужны только обратные вызовы (продолжения).Такие функции, как ваша stringToLower, должны только возвращать данные.

function string_to_lower (str) {
  return str.toLowerCase();
}

Если бы вы настроили свой код в соответствии с этими правилами, вы могли бы сделать что-то более знакомое:

function TermFrequency(){
  read_file(myArgs[0],function(result){
   write_out( sort(frequencies(remove_stop_words(remove_non_alphanumeric(string_to_lower(result))))));
  }
}

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

function compose (...fns) {
  return function (value) {
    fns.reduce(function (result, fn) {
      return fn(result);
    }, value);
  }
}

, и мы можем использовать ее так:

const processFile = compose(
  string_to_lower,
  remove_non_alphanumeric,
  remove_stop_words,
  frequencies,
  sort,
  write_out,
);

function TermFrequency(){
  read_file(myArgs[0], processFile);
}

Теперь это может выглядеть чуждо, но давайте пройдемсячерез это.Функция compose принимает список аргументов с именем fns.... (оператор rest) просто принимает отдельные аргументы и помещает их в массив.Вы заметите, что функция compose возвращает другую функцию.Так что compose(omg) вернет другую функцию, ожидающую value.Когда вы указываете значение, функция отключается.Мы вызываем compose со списком функций, и он возвращает функцию, ожидающую значение.Мы назначаем эту функцию для const processFile.Затем мы выполняем нашу асинхронную операцию и устанавливаем processFile в качестве обратного вызова.Обратный вызов (наша функция compose) получает ожидаемое значение, а затем выполняет всю обработку синхронно.

Надеюсь, это прояснит некоторые вещи.Я бы также порекомендовал изучить обещания, чтобы вам не приходилось иметь дело с обратными вызовами.

JavaScript интересен тем, что изначально является асинхронным языком.Python с другой стороны нет.Это означает, что в python вы можете использовать и другие стили, но в Javascript бывают случаи, когда вы должны использовать оба стиля.

Кроме того, имейте в виду, что в JavaScript есть обратные вызовы, с помощью которых мы создали обещания, с помощью которыхмы построили Async / Await.Понимание потока обратного вызова необходимо для более эффективного использования инструментов более высокого уровня.

...