2015-11-24 3 views
2

Я пытаюсь реорганизовать следующий код node.js.Условные функции цепочки в JavaScript

Каждый случай генерирует миниатюру, привязывая другой набор преобразований GraphicMagic к изображению.

switch(style.name) { 
    case 'original': 
     gm(response.Body) 
      .setFormat('jpg').autoOrient().resize(style.w, style.h, style.option) 
      .toBuffer(function(err, buffer) { if (err) { next(err); } else { next(null, buffer); } }); 
     break; 
    case 'large': 
     gm(response.Body) 
      .setFormat('jpg').autoOrient().resize(style.w, style.h, style.option) 
      .quality(style.quality) 
      .strip().interlace('Plane') 
      .toBuffer(function(err, buffer) { if (err) { next(err); } else { next(null, buffer); } }); 
     break; 
    case 'medium': 
     gm(response.Body) 
      .setFormat('jpg').autoOrient().resize(style.w, style.h, style.option) 
      .crop(style.w, style.h, style.crop.x_offset, style.crop.y_offset) 
      .repage('+') 
      .strip().interlace('Plane') 
      .toBuffer(function(err, buffer) { if (err) { next(err); } else { next(null, buffer); } }); 
     break; 
    case 'small': 
     gm(response.Body) 
      .setFormat('jpg').autoOrient().resize(style.w, style.h, style.option) 
      .crop(style.w, style.h, style.crop.x_offset, style.crop.y_offset).repage('+') 
      .quality(style.quality) 
      .strip().interlace('Plane') 
      .toBuffer(function(err, buffer) { if (err) { next(err); } else { next(null, buffer); } }); 
     break; 
} 

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

gm(response.Body) 
.setFormat('jpg').autoOrient().resize(style.w, style.h, style.option, function(err, response) { 
    if (style.name === 'original'){ 
     return response; 
    } else if (style.name === 'large'){ 
     return response.quality(style.quality) 
    } else if (style.name === 'medium'){ 
     return response.crop(style.w, style.h, style.crop.x_offset, style.crop.y_offset).repage('+') 
    } else if (style.name === 'small'){ 
     return response.crop(style.w, style.h, style.crop.x_offset, style.crop.y_offset).repage('+').quality(style.quality) 
    } 
}).(function(response) { 
    return (stryle.name !== 'original') ? response.strip().interlace('Plane') : return response; 
}).(function(argument) { 
    return response.toBuffer(function(err, buffer) { if (err) { next(err); } else { next(null, buffer); } }); 
}); 
+1

') (' <<< это кажется странным –

+0

Кроме того, что о более удобном для восприятия объекта '{ "оригинал": resp1, "нормальный": resp2, и т.д ...}' –

+0

Мм, я не» t видеть 'resize', беря' функцию (err, response) 'callback в первом фрагменте? – Bergi

ответ

3

Я бы не пойти на switch вообще.

Здесь нет причин использовать цепочки. Просто сделайте

// if (!/^(original|large|medium|small)$/.test(style.name)) throw new Error(…); 
var x = gm(response.Body) 
     .setFormat('jpg') 
     .autoOrient() 
     .resize(style.w, style.h, style.option); 
if (style.name == "medium" || style.name == "small") 
    x = x.crop(style.w, style.h, style.crop.x_offset, style.crop.y_offset) 
     .repage('+'); 
if (style.name == "large" || style.name == "small") 
    x = x.quality(style.quality); 
if (style.name == "large" || style.name == "medium" || style.name == "small") 
// possibly better than if (style.name != "original") 
    x = x.strip() 
     .interlace('Plane'); 
x.toBuffer(next); 

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

function resizedJpg(x) { 
    return x.setFormat('jpg').autoOrient().resize(style.w, style.h, style.option); 
} 
function cropped(x) { 
    return x.crop(style.w, style.h, style.crop.x_offset, style.crop.y_offset).repage('+'); 
} 
function withQuality(x) { 
    return x.quality(style.quality); 
} 
function stripped(x) { 
    return x.strip().interlace('Plane'); 
} 

, а затем применять их по отдельности:

.
({ 
    original: [resizedJpg], 
    large: [resizedJpg,   withQuality, stripped], 
    medium: [resizedJpg, cropped,    stripped], 
    small: [resizedJpg, cropped, withQuality, stripped] 
}[style.name]).reduce(function(x, trans) { 
    return trans(x); 
}, gm(response.Body)).toBuffer(next); 
+0

Спасибо за отличный ответ! При первом подходе, поскольку мы не сразу объединяем все методы и используем промежуточную переменную x, она будет запускать gm-преобразования отдельно (один раз перед операциями if и дважды после) или будет делать их все сразу, когда мы будем называть ' toBuffer() '? – Sbbs

+0

Я беспокоюсь, что многократные вызовы преобразований также будут запускать gm несколько раз на изображении и, следовательно, вычислительно дороже, чем цепочка всех преобразований одновременно и запуск gm только один раз на изображении. – Sbbs

+1

@SBBS: Нет, 'gm' не может отличить, назначен ли он переменной или нет, если цепочка выполняется синхронно. С таким видом шаблона построения я уверен, что работа выполняется только при вызове '.toBuffer()'. Если он хорошо написан, вы можете дважды вызвать '.toBuffer()' дважды, и он будет работать ровно два раза. – Bergi