javascript - 콜백함수 - node.js를 사용하여 콜백이 호출 될 때까지 함수를 대기시키는 방법




자바스크립트 콜백함수 (8)

그건 비 차단 입출력의 목적을 무효화합니다. 차단을 필요로하지 않을 때 차단하고 있습니다. :)

node.js를 강제적으로 기다리지 않고 콜백을 중첩하거나, r 결과가 필요한 콜백 내에서 다른 콜백을 호출해야합니다.

블록킹을 강요해야하는 경우 아키텍처가 잘못되었다고 생각할 가능성이 있습니다.

나는 다음과 같은 간단한 함수를 가지고있다 :

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'방식이 무엇입니까? 콜백이 호출 될 때까지 기다리는 함수를 원한다면 전달 된 값을 반환하십시오.


나에게 그것은 사용하기 위해 일했다.

JSON.parse(result)['key']

결과에 나는 예상했다. 이것은 "수퍼 일반"이 아니지만 결국 "JSON.parse"가 비동기 호출을 기다리는 것을 관리하고 result['key'] 는 그렇지 않습니다.


다음을 확인하십시오 : https://github.com/luciotato/waitfor-ES6

wait.for를 사용하는 코드 : (생성자가 필요합니다 - harmony 플래그)

function* (query) {
  var r = yield wait.for( myApi.exec, 'SomeCommand');
  return r;
}

매우 간단하고 쉬운 경우 다른 코드를 실행하기 전에 노드에서 콜백 함수가 실행될 때까지 기다리는 멋진 라이브러리는 다음과 같습니다.

//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();
}

이것을 달성하는 한 가지 방법은 API 호출을 약속으로 랩 한 다음 결과를 기다리는 것을 기다리는 것입니다.

// 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

콜백을 사용하지 않으려면 "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


참고 :이 답변은 프로덕션 코드에서 사용하지 않아야합니다. 그것은 해킹이며 그 의미에 대해 알아야합니다.

libuv 메인 이벤트 루프 (Nodejs 메인 루프)의 단일 루프 라운드를 실행할 수있는 uvrun 모듈 ( here 에 새로운 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의 모든 목적을 무효로합니다. 즉 모든 것이 비동기적이고 비 차단되도록하는 것입니다. 또한 콜 스택 깊이를 많이 늘릴 수 있으므로 스택 오버플로가 발생할 수 있습니다. 이러한 함수를 재귀 적으로 실행하면 확실히 문제가 발생할 것입니다.

코드를 "올바르게"다시 디자인하는 방법에 대한 다른 대답을 참조하십시오.

이 해결책은 아마 당신이 테스트를 할 때만 유용하다. 동기화 및 일련 번호를 원합니다.


exports.dbtest = function (req, res) {
  db.query('SELECT * FROM users', [], res, renderDbtest);
};

function renderDbtest(result, res){
  res.render('db', { result: result });
}

여기 내가 어떻게했는지, 그냥 "res"와 함께 전달해야하므로 나중에 렌더링 할 수있다.





node.js