Node.js/Node.js μ‹€μŠ΅

node js async λͺ¨λ“ˆ μ‚¬μš©ν•˜κΈ°

λŒ•λŒ•μ΄λ°œπŸΎ 2018. 7. 20. 15:43



Node λŠ” 기본적으둜 λΉ„λ™κΈ°μ‹μœΌλ‘œ μž‘λ™μ„ ν•©λ‹ˆλ‹€. 즉  1 2 3 4 5 μˆœμ„œλ‘œ 코딩을 ν–ˆμ–΄λ„ λ°˜λ“œμ‹œ 1 2 3 4 5 의 μˆœμ„œλ‘œ 싀행을 ν•˜μ§„ μ•ŠλŠ” λ‹€λŠ” μ–˜κΈ°μž…λ‹ˆλ‹€. μ„œλ²„μͺ½μ—μ„œλŠ” λΉ„λ™κΈ°μ‹μœΌλ‘œ μž‘λ™ν•˜λŠ” 것이 더 효율적인 상황이 λ§Žμ§€λ§Œ λ°˜λ“œμ‹œ 순차적으둜 μž‘λ™ν•΄μ•Όν•  ν”„λ‘œμ„ΈμŠ€λ„ 있기 λ§ˆλ ¨μž…λ‹ˆλ‹€. μ œκ°€ μž‘μ—…ν–ˆλ˜ κ³Όμ • 쀑 κ·ΈλŸ¬ν•œ 과정이 μžˆμ–΄μ„œ asyncλΌλŠ” λͺ¨λ“ˆμ—μ„œ waterfall을 μ‚¬μš©ν•œ κ²½ν—˜ 및 μ½”λ“œλ₯Ό 써보고자 ν•©λ‹ˆλ‹€. 일단 제 과정은 μ΄λ ‡μŠ΅λ‹ˆλ‹€.




μ›Ή μƒμ—μ„œ 컴파일이 κ°€λŠ₯ν•œ 에디터λ₯Ό κ΅¬ν˜„ν•˜μ˜€λŠ”λ° 과정을 λ³΄μ‹œλ©΄ μ•„μ‹œκ² μ§€λ§Œ μž‘μ„±λ˜μ§€λ„ μ•Šμ€ νŒŒμΌμ„ 컴파일 ν•  μˆ˜λ„ 없을 것이고 컴파일이 μ•ˆλœ νŒŒμΌμ„ μ‹€ν–‰ν•˜λŠ” 것도 λ‹Ήμ—°νžˆ λΆˆκ°€λŠ₯ ν•  κ²ƒμž…λ‹ˆλ‹€. κ·Έλž˜μ„œ μœ„μ™€ 같은 과정은 λ™κΈ°μ μœΌλ‘œ μ΄λ£¨μ–΄μ Έμ•Όν•˜λŠ” 과정이기 λ•Œλ¬Έμ— κ·Έλƒ₯ 순차적인 μ½”λ“œ ν˜Ήμ€ ν•¨μˆ˜ ν˜•νƒœλ‘œ 짜면 μ•ˆλ˜κ³  μ½œλ°±ν˜•μ‹μ„ μ΄μš©ν•˜λŠ” 동기적인 ν˜•νƒœλ‘œ μž‘μ„±ν•΄μ•Ό ν–ˆμŠ΅λ‹ˆλ‹€.



전체적인 μ½”λ“œμž…λ‹ˆλ‹€.

let fs = require('fs');
let spawn = require('child_process').spawn;
let cp = require('child_process');
let exec = require('child_process').exec;
let models = require('../models');
let async = require('async');
function compileFunction(lan,path,source,res){
	let file, compile,run,responseData;
	let tasks = [
		//파일 μž‘μ„±
		function(callback){
			if(lan==='c')
				file = path+'test.c';
			else if(lan==='java')
				file = path+'Test.java';
			else if(lan==='python')
				file = path+'test.py';
			fs.writeFile(file,source,'utf-8',err=>{if(err) throw err;});
			callback(null,file);
		},
		//μž‘μ„±λœ νŒŒμΌμ„ 컴파일
		function(file,callback){
			if(lan==='c'){
				compile = exec('gcc test.c',{cwd:'sources'},(err,stdout,stderr)=>{
					if(stderr.length===0){
						let run = spawn('./sources/./a.out',[]);
						run.stdout.on('data',stdout=>{
							callback(null,stdout.toString('utf8'));
						})
					}		
					else
						callback(true,stderr)
				})
			}
			else if(lan==='java'){
				compile = exec('javac Test.java',{cwd:'sources'},(err,stdout,stderr)=>{
					if(stderr.length===0) {
						let run = exec("java Test",{cwd:'sources'},(err,stdout,stderr)=>{
							callback(null,stdout);
						});
					}
					else
						callback(true,stderr)
				})
			}
			else if(lan==='python'){
				compile = exec('python3 test.py',{cwd:'sources'},(err,stdout,stderr)=>{
					if(stderr.length===0) {
						callback(null,stdout)
					}
					else 
						callback(true,stderr)
				})
			}
		},
		//컴파일 ν›„ λ‚˜μ˜¨ κ²°κ³Όλ₯Ό λ°˜ν™˜
		function(stdout,callback){
			callback(null,stdout)
		}
	]
	async.waterfall(tasks,(err,msg)=>{
		if(err){
			responseData = {'result':'err','output':msg};
			res.json(responseData);
		}
		else{
			responseData = {'result':'ok','output':msg};
			res.json(responseData);
			console.log('done');
		}
	});
}
exports.compileFunction = compileFunction;



μ œλŒ€λ‘œ μ‹€ν–‰λ˜λŠ” κ²ƒλ§Œ ν™•μΈν•˜κ³  아직 λ‹€λ“¬μ§€λŠ” μ•Šμ€ μƒνƒœμ—¬μ„œ μ½”λ“œκ°€ μ§€μ €λΆ„ν•œ μƒνƒœμž…λ‹ˆλ‹€. waterfallμ΄λΌλŠ”κ²Œ 말 κ·ΈλŒ€λ‘œ 폭포수의  ν˜•νƒœλ₯Ό λˆλ‹€κ³  ν•΄μ„œ λΆ™μ—¬μ§„ 이름인데 function이 마치 폭포수처럼 λ‚˜μ—΄λ˜λ©°, 전단계 ν•¨μˆ˜μ˜ κ²°κ³Όλ₯Ό λ‹€μŒ λ‹¨κ³„μ˜ λ³€μˆ˜κ°’μœΌλ‘œ μ‚¬μš©  κ°€λŠ₯ν•œ callback ν˜•νƒœλ₯Ό 띄고 μžˆμŠ΅λ‹ˆλ‹€. μ‚¬μš©μž λͺ¨λ“ˆν˜•νƒœλ‘œ μ“°κΈ°μœ„ν•΄μ„œ λ”°λ‘œ λΆ„λ¦¬μ‹œμΌœ 놓은 js νŒŒμΌμ΄κΈ°λ•Œλ¬Έμ— λ§€κ°œλ³€μˆ˜λ„  이미 app.js νŒŒμΌμ—μ„œ λ„˜μ–΄μ˜¨ μƒνƒœμΈλ° 그런건 μ œμ³λ‘κ³  λ™μž‘ κ³Όμ •λ§Œ μ„€λͺ…ν•΄λ³΄κ² μŠ΅λ‹ˆλ‹€.



let tasks = [
        //파일 μž‘μ„±
        function(callback){
            if(lan==='c')
                file = path+'test.c';
            else if(lan==='java')
                file = path+'Test.java';
            else if(lan==='python')
                file = path+'test.py';
            fs.writeFile(file,source,'utf-8',err=>{if(err) throw err;});
            callback(null,file);
        },
        //μž‘μ„±λœ νŒŒμΌμ„ 컴파일
        function(file,callback){
            if(lan==='c'){
                compile = exec('gcc test.c',{cwd:'sources'},(err,stdout,stderr)=>{
                    if(stderr.length===0){
                        let run = spawn('./sources/./a.out',[]);
                        run.stdout.on('data',stdout=>{
                            callback(null,stdout.toString('utf8'));
                        })
                    }       
                    else
                        callback(true,stderr)
                })
            }
            else if(lan==='java'){
                compile = exec('javac Test.java',{cwd:'sources'},(err,stdout,stderr)=>{
                    if(stderr.length===0) {
                        let run = exec("java Test",{cwd:'sources'},(err,stdout,stderr)=>{
                            callback(null,stdout);
                        });
                    }
                    else
                        callback(true,stderr)
                })
            }
            else if(lan==='python'){
                compile = exec('python3 test.py',{cwd:'sources'},(err,stdout,stderr)=>{
                    if(stderr.length===0) {
                        callback(null,stdout)
                    }
                    else
                        callback(true,stderr)
                })
            }
        },
        //컴파일 ν›„ λ‚˜μ˜¨ κ²°κ³Όλ₯Ό λ°˜ν™˜
        function(stdout,callback){
            callback(null,stdout)
        }
    ]

=> λ™κΈ°μ μœΌλ‘œ μž‘λ™ν•΄μ•Όν•  function듀을 λ°°μ—΄ν˜•νƒœλ‘œ μž‘μ„±ν•΄μ€€ κ²ƒμž…λ‹ˆλ‹€. μ•„κΉŒ μœ„μ—μ„œλ„ 흐름도λ₯Ό μ²¨λΆ€ν•˜μ˜€λŠ”λ° 거기에 μ•½κ°„μ˜ μ„€λͺ…을 λ”ν•΄λ³΄κ² μŠ΅λ‹ˆλ‹€.



μ € 빨간색 μš”κ΅¬μ‚¬ν•­λ“€μ΄ callback ν•¨μˆ˜μ˜ λ§€κ°œλ³€μˆ˜λ‘œ λ“€μ–΄κ°ˆ κ°’λ“€μž…λ‹ˆλ‹€. νŒŒμΌμ„ μ „λ‹¬ν•΄μ€˜μ•Ό μ»΄νŒŒμΌμ„ ν• ν…Œκ³  μ‹€ν–‰νŒŒμΌμ΄ μžˆμ–΄μ•Ό  싀행을 ν•˜κ² μ£  ꡉμž₯히 λ‹¨μˆœν•œ μ΄μΉ˜μž…λ‹ˆλ‹€. 항상 ν•¨μˆ˜μ˜ 끝에 callback(null, 전달할 λ³€μˆ˜) 의 ν˜•νƒœλ‘œ ν˜ΈμΆœμ„ ν•˜λŠ” 것을 λ³Ό 수 μžˆμŠ΅λ‹ˆλ‹€. 근데 null은 λ„λŒ€μ²΄ μ™œ λ“€μ–΄κ°€λŠ”κ±΄κ°€ κΆκΈˆν•΄μ„œ 저도 μ°Ύμ•„ λ΄€μŠ΅λ‹ˆλ‹€.



ꡬ글 λ²ˆμ—­κΈ°μ˜ λ„μ›€μœΌλ‘œ λ²ˆμ—­μ„ ν•΄λ³΄λ‹ˆ

--------------------google λ²ˆμ—­-------------------------

일반적으둜 λ…Έλ“œμ—μ„œ 콜백의 첫 번째 μΈμˆ˜λŠ” 일반적으둜 였λ₯˜λ₯Ό λ‚˜νƒ€λ‚΄λŠ” 데 μ‚¬μš©λ©λ‹ˆλ‹€. 그것이 null이 μ•„λ‹Œ λ‹€λ₯Έ 것이라면, μ–΄λ–€ 이유둜 λ“  μž‘μ—…μ΄ μ‹€νŒ¨ν–ˆμŠ΅λ‹ˆλ‹€. μ•„λ§ˆλ„ 호좜 μˆ˜μ‹ μžκ°€ 볡ꡬ ν•  수 μ—†μ§€λ§Œ ν˜ΈμΆœμžκ°€ 볡ꡬ ν•  μˆ˜μžˆλŠ” 것일 수 μžˆμŠ΅λ‹ˆλ‹€. 첫 번째 인수 μ΄ν›„μ˜ λ‹€λ₯Έ μΈμˆ˜λŠ” μ—°μ‚°μ˜ λ°˜ν™˜ κ°’μœΌλ‘œ μ‚¬μš©λ©λ‹ˆλ‹€ (μ„±κ³΅ν•œ λ©”μ‹œμ§€, 검색 λ“±).

---------------------------------------------------------


라고 해석이 λ‚˜μ˜΅λ‹ˆλ‹€. λΆ„μœ„κΈ°μƒ 마치 κ΄€μŠ΅μ μœΌλ‘œ κ·Έλ ‡κ²Œ 쓰인닀 λΌλŠ” λ‰˜μ•™μŠ€λ₯Ό λ³΄μ΄λŠ”κ±Έ λ³΄λ‹ˆ λ‹€λ₯Έ μ–Έμ–΄μ—μ„œλŠ” 아닐 μˆ˜λ„ μžˆκ² μ§€λ§Œ nodeμ—μ„œλŠ” κ΄€μŠ΅μ μœΌλ‘œ κ·Έλ ‡κ²Œ μ“°λ‚˜λ³΄λ‹€ ν•˜κ³  일단 λ„˜μ–΄κ°€κ² μŠ΅λ‹ˆλ‹€. 즉 μš°λ¦¬κ°€ 신경써야할 μΈμˆ˜λŠ” 첫 번째 인수 μ΄ν›„λΌλŠ” κ²ƒμž…λ‹ˆλ‹€.


μ•„λ¬΄νŠΌ λ°°μ—΄ν˜•νƒœλ‘œ μ—¬λŸ¬κ°œμ˜ ν•¨μˆ˜λ₯Ό λͺ¨λ‘ μž‘μ„±ν–ˆλ‹€ 치면 λ™κΈ°μ‹μœΌλ‘œ μž‘λ™μ‹œν‚€λŠ” 방법은 κ°„λ‹¨ν•©λ‹ˆλ‹€.

async.waterfall(tasks,(err,msg)=>{
		if(err){
			responseData = {'result':'err','output':msg};
			res.json(responseData);
		}
		else{
			responseData = {'result':'ok','output':msg};
			res.json(responseData);
			console.log('done');
		}
	});


async의 waterfall을 μ΄μš©ν•˜μ—¬ λ§€κ°œλ³€μˆ˜λ‘œ μž‘μ„±ν•œ ν•¨μˆ˜μ˜ λ°°μ—΄κ³Ό μ½œλ°±ν•¨μˆ˜λ₯Ό μ΄μš©ν•˜μ—¬ μ œλŒ€λ‘œ 싀행이 λλŠ”μ§€ 확인할 수 μžˆμŠ΅λ‹ˆλ‹€. μ•„λ‹ˆλ©΄ 각 ν•¨μˆ˜μ˜ λ‹¨κ³„λ§ˆλ‹€ logλ₯Ό μ°μ–΄μ„œ λ‚΄κ°€ μƒκ°ν•œ μˆœμ„œλŒ€λ‘œ μ‹€ν–‰λ˜κ³  μžˆλŠ”μ§€ ν™•μΈν•˜μ…”λ„ λ©λ‹ˆλ‹€.

λŒ“κΈ€μˆ˜0