Node.js에서 비동기 함수의 긴 중첩을 피하는 방법
DB의 일부 데이터를 표시하는 페이지를 만들고 싶습니다. 따라서 DB에서 해당 데이터를 가져 오는 함수를 만들었습니다. 나는 Node.js의 초보자 일 뿐이므로 이해하는 한 모든 페이지를 단일 페이지 (HTTP 응답)로 사용하려면 모두 중첩해야합니다.
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/html'});
var html = "<h1>Demo page</h1>";
getSomeDate(client, function(someData) {
html += "<p>"+ someData +"</p>";
getSomeOtherDate(client, function(someOtherData) {
html += "<p>"+ someOtherData +"</p>";
getMoreData(client, function(moreData) {
html += "<p>"+ moreData +"</p>";
res.write(html);
res.end();
});
});
});
이와 같은 함수가 많으면 중첩이 문제가 됩니다.
이것을 피할 수있는 방법이 있습니까? 여러 비동기 함수를 결합하는 방법과 관련이 있다고 생각합니다. 이것은 근본적인 것으로 보입니다.
흥미로운 관찰. JavaScript에서는 일반적으로 인라인 익명 콜백 함수를 명명 된 함수 변수로 바꿀 수 있습니다.
다음과 같은:
http.createServer(function (req, res) {
// inline callback function ...
getSomeData(client, function (someData) {
// another inline callback function ...
getMoreData(client, function(moreData) {
// one more inline callback function ...
});
});
// etc ...
});
다음과 같이 다시 작성 될 수 있습니다.
var moreDataParser = function (moreData) {
// date parsing logic
};
var someDataParser = function (someData) {
// some data parsing logic
getMoreData(client, moreDataParser);
};
var createServerCallback = function (req, res) {
// create server logic
getSomeData(client, someDataParser);
// etc ...
};
http.createServer(createServerCallback);
그러나 다른 곳에서 콜백 논리를 재사용하려는 경우가 아니라면 예와 같이 인라인 익명 함수를 읽는 것이 훨씬 쉽습니다. 또한 모든 콜백의 이름을 찾지 않아도됩니다.
또한 아래 주석에 언급 된 @pst 에서 내부 함수 내에서 클로저 변수에 액세스하는 경우 위의 내용은 간단한 번역이 아닙니다. 이러한 경우 인라인 익명 함수를 사용하는 것이 훨씬 더 좋습니다.
케이, 간단히이 모듈 중 하나를 사용하십시오.
이것을 돌릴 것입니다 :
dbGet('userIdOf:bobvance', function(userId) {
dbSet('user:' + userId + ':email', 'bobvance@potato.egg', function() {
dbSet('user:' + userId + ':firstName', 'Bob', function() {
dbSet('user:' + userId + ':lastName', 'Vance', function() {
okWeAreDone();
});
});
});
});
이것으로 :
flow.exec(
function() {
dbGet('userIdOf:bobvance', this);
},function(userId) {
dbSet('user:' + userId + ':email', 'bobvance@potato.egg', this.MULTI());
dbSet('user:' + userId + ':firstName', 'Bob', this.MULTI());
dbSet('user:' + userId + ':lastName', 'Vance', this.MULTI());
},function() {
okWeAreDone()
}
);
대부분 Daniel Vassallo에 동의합니다. 복잡하고 깊이 중첩 된 함수를 별도의 명명 된 함수로 나눌 수 있다면 일반적으로 좋은 생각입니다. 단일 함수 내에서 수행하는 것이 합리적 인 경우에는 사용 가능한 많은 node.js 비동기 라이브러리 중 하나를 사용할 수 있습니다. 사람들은이 문제를 해결하기 위해 다양한 방법을 생각해 냈으므로 node.js 모듈 페이지를보고 여러분의 생각을보십시오.
나는 이것을 위해 async.js 라는 모듈을 작성했다 . 이를 사용하여 위 예제를 다음과 같이 업데이트 할 수 있습니다.
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/html'});
async.series({
someData: async.apply(getSomeDate, client),
someOtherData: async.apply(getSomeOtherDate, client),
moreData: async.apply(getMoreData, client)
},
function (err, results) {
var html = "<h1>Demo page</h1>";
html += "<p>" + results.someData + "</p>";
html += "<p>" + results.someOtherData + "</p>";
html += "<p>" + results.moreData + "</p>";
res.write(html);
res.end();
});
});
이 접근법의 한 가지 좋은 점은 'series'함수를 'parallel'로 변경하여 데이터를 병렬로 가져 오기 위해 코드를 빠르게 변경할 수 있다는 것입니다. 또한 async.js는 브라우저 내에서도 작동하므로 까다로운 비동기 코드가 발생하는 경우 node.js에서와 동일한 방법을 사용할 수 있습니다.
도움이 되길 바랍니다.
중첩 된 함수 나 모듈이 아닌 배열에이 트릭을 사용할 수 있습니다.
눈에 훨씬 쉽게.
var fs = require("fs");
var chain = [
function() {
console.log("step1");
fs.stat("f1.js",chain.shift());
},
function(err, stats) {
console.log("step2");
fs.stat("f2.js",chain.shift());
},
function(err, stats) {
console.log("step3");
fs.stat("f2.js",chain.shift());
},
function(err, stats) {
console.log("step4");
fs.stat("f2.js",chain.shift());
},
function(err, stats) {
console.log("step5");
fs.stat("f2.js",chain.shift());
},
function(err, stats) {
console.log("done");
},
];
chain.shift()();
병렬 프로세스 또는 병렬 프로세스 체인에 대한 관용구를 확장 할 수 있습니다.
var fs = require("fs");
var fork1 = 2, fork2 = 2, chain = [
function() {
console.log("step1");
fs.stat("f1.js",chain.shift());
},
function(err, stats) {
console.log("step2");
var next = chain.shift();
fs.stat("f2a.js",next);
fs.stat("f2b.js",next);
},
function(err, stats) {
if ( --fork1 )
return;
console.log("step3");
var next = chain.shift();
var chain1 = [
function() {
console.log("step4aa");
fs.stat("f1.js",chain1.shift());
},
function(err, stats) {
console.log("step4ab");
fs.stat("f1ab.js",next);
},
];
chain1.shift()();
var chain2 = [
function() {
console.log("step4ba");
fs.stat("f1.js",chain2.shift());
},
function(err, stats) {
console.log("step4bb");
fs.stat("f1ab.js",next);
},
];
chain2.shift()();
},
function(err, stats) {
if ( --fork2 )
return;
console.log("done");
},
];
chain.shift()();
나는 이 목적으로 async.js 를 많이 좋아 합니다.
폭포 명령으로 문제가 해결됩니다.
폭포 (작업, [콜백])
각 함수의 결과를 배열의 다음 함수로 전달하는 일련의 함수 배열을 실행합니다. 그러나 함수 중 하나라도 콜백에 오류를 전달하면 다음 함수가 실행되지 않고 오류와 함께 기본 콜백이 즉시 호출됩니다.
인수
tasks-실행할 함수 배열. 각 함수에는 완료시 호출해야하는 콜백 (err, result1, result2, ...)이 전달됩니다. 첫 번째 인수는 오류 (null 일 수 있음)이며 추가 인수는 다음 작업에 인수로 전달됩니다. callback (err, [results])-모든 기능이 완료되면 실행할 선택적 콜백입니다. 마지막 작업의 콜백 결과가 전달됩니다.
예
async.waterfall([
function(callback){
callback(null, 'one', 'two');
},
function(arg1, arg2, callback){
callback(null, 'three');
},
function(arg1, callback){
// arg1 now equals 'three'
callback(null, 'done');
}
], function (err, result) {
// result now equals 'done'
});
req, res 변수는 전체 async.waterfall 호출을 포함하는 function (req, res) {}과 동일한 범위 내에서 공유됩니다.
뿐만 아니라 비동기는 매우 깨끗합니다. 내가 의미하는 것은 다음과 같이 많은 경우를 변경한다는 것입니다.
function(o,cb){
function2(o,function(err, resp){
cb(err,resp);
})
}
먼저 :
function(o,cb){
function2(o,cb);
}
그런 다음
function2(o,cb);
그런 다음
async.waterfall([function2,function3,function4],optionalcb)
또한 비동기를 위해 준비된 많은 미리 만들어진 함수를 util.js에서 매우 빠르게 호출 할 수 있습니다. 당신이하고 싶은 일을 연결하고 o, cb가 보편적으로 처리되도록하십시오. 이것은 전체 코딩 프로세스를 크게 가속화시킵니다.
필요한 것은 약간의 구문 설탕입니다. 이것을 확인하십시오 :
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/html'});
var html = ["<h1>Demo page</h1>"];
var pushHTML = html.push.bind(html);
Queue.push( getSomeData.partial(client, pushHTML) );
Queue.push( getSomeOtherData.partial(client, pushHTML) );
Queue.push( getMoreData.partial(client, pushHTML) );
Queue.push( function() {
res.write(html.join(''));
res.end();
});
Queue.execute();
});
꽤 깔끔 하지 않습니까? html이 배열이 된 것을 알 수 있습니다. 문자열이 불변이기 때문에 더 큰 문자열을 버리는 것보다 출력을 버퍼링하는 것이 좋습니다. 다른 이유는와의 또 다른 멋진 구문 때문입니다 bind
.
Queue
예제에서 실제로는 예제 일 뿐이며 partial
다음과 같이 구현 될 수 있습니다.
// Functional programming for the rescue
Function.prototype.partial = function() {
var fun = this,
preArgs = Array.prototype.slice.call(arguments);
return function() {
fun.apply(null, preArgs.concat.apply(preArgs, arguments));
};
};
Queue = [];
Queue.execute = function () {
if (Queue.length) {
Queue.shift()(Queue.execute);
}
};
내가 찾은 이래로 Async.js 를 사랑 합니다. async.series
긴 중첩을 피하기 위해 사용할 수 있는 기능이 있습니다.
선적 서류 비치:-
시리즈 (작업, [콜백])
일련의 기능을 직렬로 실행하십시오. 각 기능은 이전 기능이 완료된 후에 실행됩니다. [...]
인수
tasks
-실행할 함수 배열로, 각 함수에는 완료시 호출해야하는 콜백이 전달됩니다. callback(err, [results])
-모든 기능이 완료되면 실행되는 선택적 콜백. 이 함수는 배열에 사용 된 콜백에 전달 된 모든 인수의 배열을 가져옵니다.
예제 코드에 적용하는 방법은 다음과 같습니다.
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/html'});
var html = "<h1>Demo page</h1>";
async.series([
function (callback) {
getSomeData(client, function (someData) {
html += "<p>"+ someData +"</p>";
callback();
});
},
function (callback) {
getSomeOtherData(client, function (someOtherData) {
html += "<p>"+ someOtherData +"</p>";
callback();
});
},
funciton (callback) {
getMoreData(client, function (moreData) {
html += "<p>"+ moreData +"</p>";
callback();
});
}
], function () {
res.write(html);
res.end();
});
});
내가 본 가장 간단한 구문 설탕은 노드 약속입니다.
npm install node-promise || 자식 클론 https://github.com/kriszyp/node-promise
이를 사용하여 비동기 메소드를 다음과 같이 연결할 수 있습니다.
firstMethod().then(secondMethod).then(thirdMethod);
각각의 반환 값은 다음에 인수로 제공됩니다.
당신이 한 일은 비동기 패턴을 취하여 순차적으로 호출되는 3 개의 함수에 적용합니다. 각각의 함수는 시작하기 전에 이전 함수가 완료되기를 기다립니다. 즉, 동기식으로 만들었습니다 . 비동기 프로그래밍의 요점은 여러 기능을 한 번에 실행하고 각 기능이 완료 될 때까지 기다릴 필요가 없다는 것입니다.
getSomeDate ()가 getMoreData ()에 아무것도 제공하지 않는 getSomeOtherDate ()에 아무것도 제공하지 않는 경우 js가 허용하는대로 비동기식으로 호출하지 않거나 js가 허용하는 것처럼 비동기식으로 호출하지 않는 이유는 무엇입니까? 단일 기능?
플로우를 제어하기 위해 중첩을 사용할 필요가 없습니다. 예를 들어, 3 개가 모두 완료된시기를 결정한 다음 응답을 보내는 공통 함수를 호출하여 각 함수를 완료하십시오.
이 작업을 수행 할 수 있다고 가정하십시오.
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/html'});
var html = "<h1>Demo page</h1>";
chain([
function (next) {
getSomeDate(client, next);
},
function (next, someData) {
html += "<p>"+ someData +"</p>";
getSomeOtherDate(client, next);
},
function (next, someOtherData) {
html += "<p>"+ someOtherData +"</p>";
getMoreData(client, next);
},
function (next, moreData) {
html += "<p>"+ moreData +"</p>";
res.write(html);
res.end();
}
]);
});
chain () 만 구현하면 각 함수를 다음 함수에 부분적으로 적용하고 첫 번째 함수 만 즉시 호출 할 수 있습니다.
function chain(fs) {
var f = function () {};
for (var i = fs.length - 1; i >= 0; i--) {
f = fs[i].partial(f);
}
f();
}
콜백 지옥은 순수한 자바 스크립트로 쉽게 피할 수 있습니다. 아래 솔루션은 모든 콜백이 함수 (오류, 데이터) 서명을 따른다고 가정합니다.
http.createServer(function (req, res) {
var modeNext, onNext;
// closure variable to keep track of next-callback-state
modeNext = 0;
// next-callback-handler
onNext = function (error, data) {
if (error) {
modeNext = Infinity;
} else {
modeNext += 1;
}
switch (modeNext) {
case 0:
res.writeHead(200, {'Content-Type': 'text/html'});
var html = "<h1>Demo page</h1>";
getSomeDate(client, onNext);
break;
// handle someData
case 1:
html += "<p>"+ data +"</p>";
getSomeOtherDate(client, onNext);
break;
// handle someOtherData
case 2:
html += "<p>"+ data +"</p>";
getMoreData(client, onNext);
break;
// handle moreData
case 3:
html += "<p>"+ data +"</p>";
res.write(html);
res.end();
break;
// general catch-all error-handler
default:
res.statusCode = 500;
res.end(error.message + '\n' + error.stack);
}
};
onNext();
});
최근에 wait.for 라는 간단한 추상화를 만들어 동기화 모드에서 비동기 함수를 호출했습니다 (Fibres 기반). 초기 단계이지만 작동합니다. 현재 :
https://github.com/luciotato/waitfor
wait.for를 사용하면 표준 nodejs 비동기 함수를 마치 동기 함수 인 것처럼 호출 할 수 있습니다.
wait.for 코드를 사용 하면 다음과 같습니다.
var http=require('http');
var wait=require('wait.for');
http.createServer(function(req, res) {
wait.launchFiber(handleRequest,req, res); //run in a Fiber, keep node spinning
}).listen(8080);
//in a fiber
function handleRequest(req, res) {
res.writeHead(200, {'Content-Type': 'text/html'});
var html = "<h1>Demo page</h1>";
var someData = wait.for(getSomeDate,client);
html += "<p>"+ someData +"</p>";
var someOtherData = wait.for(getSomeOtherDate,client);
html += "<p>"+ someOtherData +"</p>";
var moreData = wait.for(getMoreData,client);
html += "<p>"+ moreData +"</p>";
res.write(html);
res.end();
};
... 또는 덜 장황하게 만들고 싶을 때 (그리고 오류 잡기 추가)
//in a fiber
function handleRequest(req, res) {
try {
res.writeHead(200, {'Content-Type': 'text/html'});
res.write(
"<h1>Demo page</h1>"
+ "<p>"+ wait.for(getSomeDate,client) +"</p>"
+ "<p>"+ wait.for(getSomeOtherDate,client) +"</p>"
+ "<p>"+ wait.for(getMoreData,client) +"</p>"
);
res.end();
}
catch(err) {
res.end('error '+e.message);
}
};
모든 경우에 getSomeDate , getSomeOtherDate 및 getMoreData 는 마지막 매개 변수 a 함수 콜백 (err, data)을 갖는 표준 비동기 함수 여야합니다.
에서와 같이 :
function getMoreData(client, callback){
db.execute('select moredata from thedata where client_id=?',[client.id],
,function(err,data){
if (err) callback(err);
callback (null,data);
});
}
이 문제를 해결하기 위해 JS를 보이지 않게 사전 처리하는 nodent ( https://npmjs.org/package/nodent )를 작성했습니다 . 예제 코드는 (비동기, 실제로-문서를 읽습니다).
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/html'});
var html = "<h1>Demo page</h1>";
someData <<= getSomeDate(client) ;
html += "<p>"+ someData +"</p>";
someOtherData <<= getSomeOtherDate(client) ;
html += "<p>"+ someOtherData +"</p>";
moreData <<= getMoreData(client) ;
html += "<p>"+ moreData +"</p>";
res.write(html);
res.end();
});
분명히 많은 다른 솔루션이 있지만 사전 처리에는 런타임 오버 헤드가 거의 없거나 전혀 없다는 이점이 있으며 소스 맵 지원 덕분에 디버깅도 쉽습니다.
나는 같은 문제가 있었다. 필자는 노드에서 비동기 함수를 실행하는 주요 라이브러리를 보았으므로 코드를 빌드하기 위해 자연스럽지 않은 체인 (세 가지 이상의 메소드 conf 등을 사용해야 함)을 제공합니다.
몇 주 동안 간단하고 읽기 쉬운 솔루션을 개발했습니다. EnqJS를 사용해보십시오 . 모든 의견을 부탁드립니다.
대신에:
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/html'});
var html = "<h1>Demo page</h1>";
getSomeDate(client, function(someData) {
html += "<p>"+ someData +"</p>";
getSomeOtherDate(client, function(someOtherData) {
html += "<p>"+ someOtherData +"</p>";
getMoreData(client, function(moreData) {
html += "<p>"+ moreData +"</p>";
res.write(html);
res.end();
});
});
});
EnqJS로 :
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/html'});
var html = "<h1>Demo page</h1>";
enq(function(){
var self=this;
getSomeDate(client, function(someData){
html += "<p>"+ someData +"</p>";
self.return();
})
})(function(){
var self=this;
getSomeOtherDate(client, function(someOtherData){
html += "<p>"+ someOtherData +"</p>";
self.return();
})
})(function(){
var self=this;
getMoreData(client, function(moreData) {
html += "<p>"+ moreData +"</p>";
self.return();
res.write(html);
res.end();
});
});
});
코드가 이전보다 더 큰 것으로 보입니다. 그러나 이전과 같이 중첩되지 않았습니다. 보다 자연스럽게 보이기 위해 체인을 즉시라고합니다.
enq(fn1)(fn2)(fn3)(fn4)(fn4)(...)
그리고 함수 내에서 다음과 같이 반환되었습니다.
this.return(response)
나는 매우 원시적이지만 효과적인 방법으로 수행합니다. 예를 들어 부모와 자녀가있는 모델을 가져 와서 별도의 쿼리를 수행해야한다고 가정 해 보겠습니다.
var getWithParents = function(id, next) {
var getChildren = function(model, next) {
/*... code ... */
return next.pop()(model, next);
},
getParents = function(model, next) {
/*... code ... */
return next.pop()(model, next);
}
getModel = function(id, next) {
/*... code ... */
if (model) {
// return next callbacl
return next.pop()(model, next);
} else {
// return last callback
return next.shift()(null, next);
}
}
return getModel(id, [getParents, getChildren, next]);
}
Fibers https://github.com/laverdet/node-fibers를 사용 하면 비동기 코드가 동기식으로 보입니다 (차단하지 않음)
나는 개인적 으로이 작은 래퍼 http://alexeypetrushin.github.com/synchronize 내 프로젝트의 코드 샘플을 사용합니다 (모든 메소드는 실제로 비동기 적이며 비동기 파일 IO로 작업합니다). 콜백이나 콜백으로 어떤 혼란이 생길지 두려워합니다. 비동기 제어 흐름 도우미 라이브러리.
_update: (version, changesBasePath, changes, oldSite) ->
@log 'updating...'
@_updateIndex version, changes
@_updateFiles version, changesBasePath, changes
@_updateFilesIndexes version, changes
configChanged = @_updateConfig version, changes
@_updateModules version, changes, oldSite, configChanged
@_saveIndex version
@log "updated to #{version} version"
Task.js 는 다음을 제공합니다.
spawn(function*() {
try {
var [foo, bar] = yield join(read("foo.json"),
read("bar.json")).timeout(1000);
render(foo);
render(bar);
} catch (e) {
console.log("read failed: " + e);
}
});
이 대신에 :
var foo, bar;
var tid = setTimeout(function() { failure(new Error("timed out")) }, 1000);
var xhr1 = makeXHR("foo.json",
function(txt) { foo = txt; success() },
function(err) { failure() });
var xhr2 = makeXHR("bar.json",
function(txt) { bar = txt; success() },
function(e) { failure(e) });
function success() {
if (typeof foo === "string" && typeof bar === "string") {
cancelTimeout(tid);
xhr1 = xhr2 = null;
render(foo);
render(bar);
}
}
function failure(e) {
xhr1 && xhr1.abort();
xhr1 = null;
xhr2 && xhr2.abort();
xhr2 = null;
console.log("read failed: " + e);
}
다른 사람들이 응답 한 후 문제는 지역 변수라고 진술했습니다. 이 작업을 수행하는 쉬운 방법은 로컬 변수를 포함하는 하나의 외부 함수를 작성한 다음 이름이 지정된 내부 함수를 사용하여 이름으로 액세스하는 것입니다. 이런 식으로, 몇 개의 함수를 서로 연결해야하는지에 관계없이 두 개의 깊이에만 중첩됩니다.
mysql
중첩 을 사용하여 Node.js 모듈 을 사용하려는 초보자의 시도는 다음과 같습니다 .
function with_connection(sql, bindings, cb) {
pool.getConnection(function(err, conn) {
if (err) {
console.log("Error in with_connection (getConnection): " + JSON.stringify(err));
cb(true);
return;
}
conn.query(sql, bindings, function(err, results) {
if (err) {
console.log("Error in with_connection (query): " + JSON.stringify(err));
cb(true);
return;
}
console.log("with_connection results: " + JSON.stringify(results));
cb(false, results);
});
});
}
다음은 명명 된 내부 함수를 사용한 재 작성입니다. 외부 함수 with_connection
도 지역 변수의 홀더로 사용할 수 있습니다. (여기서, I는 매개 변수있어 sql
, bindings
, cb
유사한 방법으로 그 행동을하지만, 당신은 단지 몇 가지 추가 지역 변수를 정의 할 수 있습니다 with_connection
.)
function with_connection(sql, bindings, cb) {
function getConnectionCb(err, conn) {
if (err) {
console.log("Error in with_connection/getConnectionCb: " + JSON.stringify(err));
cb(true);
return;
}
conn.query(sql, bindings, queryCb);
}
function queryCb(err, results) {
if (err) {
console.log("Error in with_connection/queryCb: " + JSON.stringify(err));
cb(true);
return;
}
cb(false, results);
}
pool.getConnection(getConnectionCb);
}
인스턴스 변수로 객체를 만들고 이러한 인스턴스 변수를 로컬 변수 대신 사용할 수 있다고 생각했습니다. 그러나 이제 중첩 함수와 로컬 변수를 사용하는 위의 접근 방식이 더 간단하고 이해하기 쉽다는 것을 알았습니다. OO를 배우려면 약간의 시간이 걸립니다.
여기 객체와 인스턴스 변수가있는 이전 버전이 있습니다.
function DbConnection(sql, bindings, cb) {
this.sql = sql;
this.bindings = bindings;
this.cb = cb;
}
DbConnection.prototype.getConnection = function(err, conn) {
var self = this;
if (err) {
console.log("Error in DbConnection.getConnection: " + JSON.stringify(err));
this.cb(true);
return;
}
conn.query(this.sql, this.bindings, function(err, results) { self.query(err, results); });
}
DbConnection.prototype.query = function(err, results) {
var self = this;
if (err) {
console.log("Error in DbConnection.query: " + JSON.stringify(err));
self.cb(true);
return;
}
console.log("DbConnection results: " + JSON.stringify(results));
self.cb(false, results);
}
function with_connection(sql, bindings, cb) {
var dbc = new DbConnection(sql, bindings, cb);
pool.getConnection(function (err, conn) { dbc.getConnection(err, conn); });
}
그것은 bind
어떤 이점으로 사용될 수 있음 이 밝혀졌습니다 . 메소드 호출에 자신을 전달하는 것 외에는 아무 것도하지 않은 내가 만든 다소 추악한 익명 함수를 제거 할 수 있습니다. 의 잘못된 값과 관련되어 있기 때문에 메소드를 직접 전달할 수 없습니다 this
. 그러나을 bind
사용하면 this
원하는 값을 지정할 수 있습니다 .
function DbConnection(sql, bindings, cb) {
this.sql = sql;
this.bindings = bindings;
this.cb = cb;
}
DbConnection.prototype.getConnection = function(err, conn) {
var f = this.query.bind(this);
if (err) {
console.log("Error in DbConnection.getConnection: " + JSON.stringify(err));
this.cb(true);
return;
}
conn.query(this.sql, this.bindings, f);
}
DbConnection.prototype.query = function(err, results) {
if (err) {
console.log("Error in DbConnection.query: " + JSON.stringify(err));
this.cb(true);
return;
}
console.log("DbConnection results: " + JSON.stringify(results));
this.cb(false, results);
}
// Get a connection from the pool, execute `sql` in it
// with the given `bindings`. Invoke `cb(true)` on error,
// invoke `cb(false, results)` on success. Here,
// `results` is an array of results from the query.
function with_connection(sql, bindings, cb) {
var dbc = new DbConnection(sql, bindings, cb);
var f = dbc.getConnection.bind(dbc);
pool.getConnection(f);
}
물론 Node.js 코딩을 사용한 올바른 JS는 없습니다. 방금 몇 시간을 보냈습니다. 그러나 약간의 연마 로이 기술이 도움이 될 수 있습니까?
async.js가 잘 작동합니다. 나는 예제와 함께 async.js의 필요성과 사용을 설명하는이 유용한 기사를 보았습니다 : http://www.sebastianseilund.com/nodejs-async-in-practice
"step"또는 "seq"를 사용하지 않으려면 중첩 된 비동기 콜백을 줄이기위한 간단한 함수 인 "line"을 시도하십시오.
https://github.com/kevin0571/node-line
C #과 비슷한 asyncawait는 이것을 수행하는 또 다른 방법입니다.
https://github.com/yortus/asyncawait
async(function(){
var foo = await(bar());
var foo2 = await(bar2());
var foo3 = await(bar2());
}
와이어를 사용하면 코드는 다음과 같습니다.
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/html'});
var l = new Wire();
getSomeDate(client, l.branch('someData'));
getSomeOtherDate(client, l.branch('someOtherData'));
getMoreData(client, l.branch('moreData'));
l.success(function(r) {
res.write("<h1>Demo page</h1>"+
"<p>"+ r['someData'] +"</p>"+
"<p>"+ r['someOtherData'] +"</p>"+
"<p>"+ r['moreData'] +"</p>");
res.end();
});
});
아시다시피 Jazz.js https://github.com/Javanile/Jazz.js/wiki/Script-showcase를 고려 하십시오.
const jj = require ( 'jazz.js'); // 초소형 스택 jj.script ([ a => ProcessTaskOneCallbackAtEnd (a), b => ProcessTaskTwoCallbackAtEnd (b), c => ProcessTaskThreeCallbackAtEnd (c), d => ProcessTaskFourCallbackAtEnd (d), e => ProcessTaskFiveCallbackAtEnd (e), ]);
'Programing' 카테고리의 다른 글
virtualenv에 해당하는 루비? (0) | 2020.06.06 |
---|---|
정적 확장 방법 (0) | 2020.06.06 |
Entity Framework : 기본 키가없는 테이블 (0) | 2020.06.06 |
C ++ 라이브러리 및 프레임 워크가 스마트 포인터를 사용하지 않는 이유는 무엇입니까? (0) | 2020.06.06 |
activerecord로 마지막 N 레코드를 얻는 방법은 무엇입니까? (0) | 2020.06.05 |