2016-11-28 5 views
1

누구나 오류 로깅을 사용하여 파이프 라인을 처리하는 관용적 인 기능적 방법을 제안 할 수 있습니까? 샘플 명령형 (JavaScript) :오류 로깅과 함께 처리 파이프 라인을 처리하는 관용적 인 기능적 방법은 무엇입니까?

const filesToProcess = ['file1.txt','file2.txt','non_existent_file.txt']; 

var totalLetterCountImperative = 0; 
for (var i = 0; i < filesToProcess.length; i++){ 
    try { 
     totalLetterCountImperative += fs.readFileSync(filesToProcess[i],'utf8').length; 
    } catch (e) { 
     console.log("There is an error whilst processing file: " + filesToProcess[i] + ". Hence, it's skipped. Error: " + e.message); 
    } 
} 
console.log("Total Letter Count: " + totalLetterCountImperative); 

아래의 시도는 효과가 있지만 어색하고 어색합니다. 또한, 모든 오류에 대한 일반적인 아니다 :

const filesToProcess = ['file1.txt','file2.txt','non_existent_file.txt']; 

const totalLetterCount = filesToProcess 
          .filter(f => fs.existsSync(f)) 
          .map(f => fs.readFileSync(f,'utf8').length) 
          .reduce((a,b) => a+b); 

filesToProcess 
    .filter(f => !fs.existsSync(f)) 
    .map(f => console.error("There is an error whilst processing file: " + f +". Hence it's skipped. Error: File doesn't exist")); 

console.log("Total Letter Count: " + totalLetterCount); 

내가 Either의 사용에 대해 읽어보십시오. 참으로 관용적 인 방법이라면 누군가가 예제를 제공하고 사용할 수있는 좋은 JavaScript 라이브러리를 제안 할 수 있습니까?

감사합니다.

+1

당신이 오류에 파이프 라인을 포기'Either' 모나드를 사용하지만, 당신은 단지 오류를 기록하지만 파이프 라인을 계속 할 경우'Writer' 모나드를 사용하려면 . 빠른 Google 검색에서 JS 라이브러리를 찾을 수있었습니다. – 4castle

+1

아마 모나드가 필요하지 않을 수도 있습니다. [확인] (https://github.com/folktale/data.validation) 신청자를 확인하십시오.그것은 '모두'와 비슷하게 작동하지만 단락이 없으며 오류 처리를 목적으로하는 어휘가 있습니다. – ftor

답변

0

처리하는 각 단계에서 "문자 수"또는 "콘솔 메시지"결과가 생성됩니다. 내 의견으로는,

const filesToProcess = ['file1.txt','file2.txt','non_existent_file.txt']; 

var results = filesToProcess.map(function(f){ 
    try { 
     var n = readFileSync(filesToProcess[i],'utf8').length; 
     return {tag:"count", value: n}; 
    } catch (e) { 
     var msg = "There is an error whilst processing file: " + filesToProcess[i] + ". Hence, it's skipped. Error: " + e.message); 
     return {tag:"err", value:msg}; 
    } 
}) 

var totalLetterCount = 
    results 
     .filter(r => r.tag === "count") 
     .map(r => r.value) 
     .reduce((a,b)=> a + b); 

results 
    .filter(r => t.tag == "error") 
    .map(r => r.value) 
    .map(msg => console.error(msg)); 

그러나이 문제를 해결하는 가장 간단한 가장 직접적인 방법 중 하나는 첫 번째 패스는 두 번째 패스이 개 균일 목록으로 사람들을 분리 할 이들 값의 이기종 목록을 작성하는 것입니다 더 나은 해결책은 부작용을 이용하고 console.error를 사용하는 것입니다. 이미 필수 스 니펫에서 수행하고있는 것처럼 말입니다. 이 방법을 사용하면 사물을 합산하고 오류를 로깅하는 교차 절단 문제를 함께 혼합 할 필요가 없으며 "순전히 기능적인"솔루션을 고집하는 경우 얻을 수있는 것보다 훨씬 더 유사한 결과를 얻게됩니다.

저는 Ocaml에서 프로그래밍 할 때 항상 이런 종류의 일을합니다. 복잡 한 모나드 및/또는 모나드 변형자를 사용하기 위해 모든 것을 리펙토링하는 것보다 대기열에 "기록 된"값을 추가하는 부작용을 사용하는 것이 훨씬 간단합니다.

0

//이 내 구현하여 RamdaJS와 민화

const fs = require('fs'); 
const R = require('ramda'); 
const Result = require('folktale/result'); 

const filesToProcess = ['1.txt','2.txt','non_existent_file.txt']; 

const processFile = function(file){ 
    try { 
     const count = fs.readFileSync(file,'utf8').length; 
     return Result.Ok(count); 
    } catch (e) { 
     return Result.Error(`Error whilst processing ${file}. It's skipped.\n`); 
    } 
}; 

const splitEithers = R.groupBy(el => (
    Result.Error.hasInstance(el)) 
     ? 'errors' 
     : 'counts' 
); 

const doMath = (processedFiles) => { 
    const totalCount = 
     processedFiles 
      .counts 
      .reduce((n, okNumber) => R.add(n, okNumber.getOrElse(0)), 0); 

    const errors = 
     processedFiles 
      .errors 
      .reduce((msg, errorMessage) => 
       msg + errorMessage.matchWith({Error: n => n.value})); 

    return [errors, totalCount]; 
}; 

const FX = ([errors, count]) => { 
    console.log(`Total word count: ${count}`); 
    console.log(errors); 
}; 

const main = R.pipe(
    R.map(processFile), 
    splitEithers, 
    doMath, 
    FX 
); 

main(filesToProcess); 
0

여기에서 네이티브 모듈을 사용하여 관용적 ES6의 접근 방식이 될 것입니다 :

const fs = require('fs') 
const { promisify } = require('util') 
const access = promisify(fs.access) 
const readFile = promisify(fs.readFile) 

const filesToProcess = ['file1.txt', 'file2.txt', 'non_existent_file.txt'] 

Promise.all(filesToProcess.map(file => access(file, fs.constants.R_OK) 
    .then(() => readFile(file, 'utf8')) 
    .catch(error => { 
    console.log(`There is an error whilst processing file: ${file}. Hence, it's skipped. Error: ${error.message}`) 

    return { length: 0 } 
    }) 
)).then(files => { 
    const totalLetterCount = files.reduce((a, b) => a.length + b.length, 0) 

    console.log(`Total Letter Count: ${totalLetterCount}`) 
}) 

util.promisify()가 비동기로 콜백 스타일의 기능을 변환 할 수는 함수 (즉, Promise을 반환하는 함수). 이를 통해 우리는 동기 함수의 사용을 피하고 백그라운드 프로세스를 기다릴 때 스레드의 제어를 해제하여 스레드가 다른 작업을 동시에 실행할 수 있도록합니다.

또한 fs.exists()은 현재 사용되지 않으므로 대신 fs.access()을 사용하기로했습니다.

아주 사소한이었다 마지막 변화는 예상대로 length 1의 배열이 여전히 제대로 줄일 수 있도록 대신과 같이 첫 번째 요소를 반환하는, Array#reduce()0의 선택적 인수를 공급하기 위해 간단했다 :

const totalLength = [{ length: 5 }].reduce((a, b) => a.length + b.length) 
 
// since we didn't supply the optional argument, we didn't get `5` like we expected 
 
console.log(totalLength)