다음과 같은 단순화 된 기능이 있습니다.
function(query) {
myApi.exec('SomeCommand', function(response) {
return response;
});
}
기본적으로 나는 그것을 호출 myApi.exec
하고 콜백 람다에 주어진 응답을 반환하고 싶다 . 그러나 위의 코드는 작동하지 않으며 즉시 반환됩니다.
매우 hackish 시도를 위해, 나는 작동하지 않는 아래를 시도했지만 적어도 내가 달성하려고하는 아이디어를 얻습니다.
function(query) {
var r;
myApi.exec('SomeCommand', function(response) {
r = response;
});
while (!r) {}
return r;
}
기본적으로 이것에 대해 좋은 ‘node.js / event driven’방법은 무엇입니까? 콜백이 호출 될 때까지 함수가 기다린 다음 전달 된 값을 반환하고 싶습니다.
답변
이것을하는 “good node.js / event driven”방법은 기다리지 않는 것 입니다.
노드와 같은 이벤트 중심 시스템으로 작업 할 때 거의 모든 것과 마찬가지로 함수는 계산이 완료되면 호출되는 콜백 매개 변수를 받아 들여야합니다. 호출자는 정상적인 의미에서 값이 “반환”될 때까지 기다리지 말고 결과 값을 처리 할 루틴을 보내십시오.
function(query, callback) {
myApi.exec('SomeCommand', function(response) {
// other stuff here...
// bla bla..
callback(response); // this will "return" your value to the original caller
});
}
따라서 다음과 같이 사용하지 마십시오.
var returnValue = myFunction(query);
그러나 이렇게 :
myFunction(query, function(returnValue) {
// use the return value here instead of like a regular (non-evented) return value
});
답변
이를 달성하는 한 가지 방법은 API 호출을 약속으로 래핑 한 다음 await
결과를 기다리는 데 사용하는 것입니다.
// let's say this is the API function with two callbacks,
// one for success and the other for error
function apiFunction(query, successCallback, errorCallback) {
if (query == "bad query") {
errorCallback("problem with the query");
}
successCallback("Your query was <" + query + ">");
}
// myFunction wraps the above API call into a Promise
// and handles the callbacks with resolve and reject
function apiFunctionWrapper(query) {
return new Promise((resolve, reject) => {
apiFunction(query,(successResponse) => {
resolve(successResponse);
}, (errorResponse) => {
reject(errorResponse)
});
});
}
// now you can use await to get the result from the wrapped api function
// and you can use standard try-catch to handle the errors
async function businessLogic() {
try {
const result = await apiFunctionWrapper("query all users");
console.log(result);
// the next line will fail
const result2 = await apiFunctionWrapper("bad query");
} catch(error) {
console.error("ERROR:" + error);
}
}
// call the main function
businessLogic();
산출:
Your query was <query all users>
ERROR:problem with the query
답변
이것을 확인하십시오 :
https://github.com/luciotato/waitfor-ES6
wait.for :를 사용하여 코드 생성 (제너레이터, –harmony 플래그 필요)
function* (query) {
var r = yield wait.for( myApi.exec, 'SomeCommand');
return r;
}
답변
콜백을 사용하지 않으려면 “Q”모듈을 사용하십시오.
예를 들면 다음과 같습니다.
function getdb() {
var deferred = Q.defer();
MongoClient.connect(databaseUrl, function(err, db) {
if (err) {
console.log("Problem connecting database");
deferred.reject(new Error(err));
} else {
var collection = db.collection("url");
deferred.resolve(collection);
}
});
return deferred.promise;
}
getdb().then(function(collection) {
// This function will be called afte getdb() will be executed.
}).fail(function(err){
// If Error accrued.
});
자세한 내용은 다음을 참조하십시오 : https://github.com/kriskowal/q
답변
다른 코드를 실행하기 전에 노드에서 콜백 함수가 실행될 때까지 기다리는 것이 매우 간단하고 쉬운 라이브러리는 없습니다.
//initialize a global var to control the callback state
var callbackCount = 0;
//call the function that has a callback
someObj.executeCallback(function () {
callbackCount++;
runOtherCode();
});
someObj2.executeCallback(function () {
callbackCount++;
runOtherCode();
});
//call function that has to wait
continueExec();
function continueExec() {
//here is the trick, wait until var callbackCount is set number of callback functions
if (callbackCount < 2) {
setTimeout(continueExec, 1000);
return;
}
//Finally, do what you need
doSomeThing();
}
답변
참고 :이 답변은 프로덕션 코드에서 사용해서는 안됩니다. 그것은 해킹이며 그 의미에 대해 알아야합니다.
libuv 메인 이벤트 루프 (Nodejs 메인 루프)의 단일 루프 라운드를 실행할 수 있는 uvrun 모듈 ( 여기서는 최신 Nodejs 버전 용으로 업데이트 됨 )이 있습니다.
코드는 다음과 같습니다.
function(query) {
var r;
myApi.exec('SomeCommand', function(response) {
r = response;
});
var uvrun = require("uvrun");
while (!r)
uvrun.runOnce();
return r;
}
(대체로 사용할 수도 있습니다 uvrun.runNoWait()
. 블로킹과 관련된 일부 문제를 피할 수 있지만 100 % CPU가 필요합니다.)
이 접근 방식은 Nodejs의 전체 목적을 무효화합니다. 즉, 모든 것이 비 동기화되고 차단되지 않습니다. 또한 콜 스택 깊이를 크게 늘릴 수 있으므로 스택 오버플로가 발생할 수 있습니다. 이러한 기능을 재귀 적으로 실행하면 문제가 발생할 수 있습니다.
코드를 “올바로”재 설계하는 방법에 대한 다른 답변을 참조하십시오.
이 솔루션은 테스트 및 esp를 수행 할 때만 유용합니다. 시리얼 코드를 동기화하고 싶습니다.
답변
노드 4.8.0부터 generator라는 ES6의 기능을 사용할 수 있습니다. 더 깊은 개념을 위해이 기사 를 따를 수 있습니다 . 그러나 기본적으로 생성기를 사용 하여이 작업을 수행 할 수 있습니다. 생성기를 약속하고 관리하기 위해 블루 버드 를 사용 하고 있습니다.
아래 예제와 같이 코드가 양호해야합니다.
const Promise = require('bluebird');
function* getResponse(query) {
const r = yield new Promise(resolve => myApi.exec('SomeCommand', resolve);
return r;
}
Promise.coroutine(getResponse)()
.then(response => console.log(response));