我有一个简化的函数,看起来像这样:

function(query) {
  myApi.exec('SomeCommand', function(response) {
    return response;
  });
}

我想让它调用myApi。Exec,返回回调lambda中给出的响应。然而,上面的代码不能工作,只是立即返回。

只是为了一个非常hack的尝试,我尝试了下面的工作,但至少你知道我想要实现什么:

function(query) {
  var r;
  myApi.exec('SomeCommand', function(response) {
    r = response;
  });
  while (!r) {}
  return r;
}

基本上,“node.js/事件驱动”的好方法是什么?我希望我的函数等待,直到回调被调用,然后返回传递给它的值。


当前回答

实现这一点的一种方法是将API调用封装到promise中,然后使用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 + ">");
}

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

其他回答

使用async和await要容易得多。

router.post('/login',async (req, res, next) => {
i = await queries.checkUser(req.body);
console.log('i: '+JSON.stringify(i));
});

//User Available Check
async function checkUser(request) {
try {
    let response = await sql.query('select * from login where email = ?', 
    [request.email]);
    return response[0];

    } catch (err) {
    console.log(err);

  }

}

实现这一点的一种方法是将API调用封装到promise中,然后使用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 + ">");
}

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

这违背了非阻塞IO的目的——你在不需要阻塞的时候阻塞了它:)

你应该嵌套回调,而不是强迫node.js等待,或者在需要r结果的回调中调用另一个回调。

如果您需要强制阻塞,那么很可能您对体系结构的想法是错误的。

如果你想让它非常简单,没有花哨的库,在执行一些其他代码之前,等待回调函数在node中执行,是这样的:

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

“好的node.js /事件驱动”的方法是不要等待。

与node等事件驱动系统一样,函数应该接受一个回调参数,该参数将在计算完成时被调用。调用者不应该等待正常意义上的值被“返回”,而是发送将处理结果值的例程:

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