Node.js 中的回调:两个不同代码片段的比较

Callbacks in Node.js: Comparison of two different code snippets

我一直在 Node.js 中使用回调进行一些工作,致力于 Messenger 机器人。

我写了一个函数来提取用户的名字并将其传递给另一个函数。我需要向该函数添加回调以使其正常工作。我获取用户名的函数如下所示:

function getFBUserName(callback)
{
    let graphURL = 'https://graph.facebook.com/v2.6/';
    let graphFields = '?fields=first_name,last_name,gender';
    let graphToken = '&access_token=';
    let reqURL = graphURL + usrPSID + graphFields + graphToken + config.FB_PAGE_ACCESS_TOKEN;
    let reqJSON;
    request(reqURL, function (error, response, body) {
        console.log('error:', error); // Print the error if one occurred
        console.log('statusCode:', response && response.statusCode); // Print the response 
        // status code if a response was received
        console.log(body);
        reqJSON = JSON.parse(body);
        if (reqJSON.hasOwnProperty("first_name")){
        console.log("First Name exists"); // Debugging, to see if hasOwnProperty is working
            let userName = reqJSON['first_name'];
            callback(userName);
        }
    });
}

此函数然后将回调传递给我的 handlePostback() 函数:

function handlePostback(sender_psid, received_postback) {
    let response;
    let responseText;

    // Get the payload for the postback
    let payload = received_postback.payload;

    // Set the response based on the postback payload
    if (payload === 'GET_STARTED') {
        let userName;
        getFBUserName(function (uName) {
            userName = uName;
        responseText = "Hi there " + userName + ", welcome to the bot!";
        response = {"text": responseText};
        callSendAPI(sender_psid, response);
        });
    }
}

上面的代码有效。但是如果我更改我的代码使其看起来像下面这样,它就不起作用。 userName 变量始终未定义。

function handlePostback(sender_psid, received_postback) {
    let response;
    let responseText;

    // Get the payload for the postback
    let payload = received_postback.payload;

    // Set the response based on the postback payload
    if (payload === 'GET_STARTED') {
        let userName;
        getFBUserName(function (uName) {
            userName = uName;
        });
        responseText = "Hi there " + userName + ", welcome to the bot!";
    }
    response = {"text": responseText};
    callSendAPI(sender_psid, response);
}

我想使用第二种代码结构,因为当我向我的 if 语句添加回发时,将会有很多重复的代码。在 if 语句中为回发设置 responseText 是有意义的,然后设置响应并在循环外发送消息。所以我的问题是,为什么第一个结构起作用,而第二个结构不起作用?

问题是 getFBUserName 是一个异步函数,它在完成时执行回调,因此 getFBUseName 调用下面的行可能在回调之前执行。

尝试执行这段代码,您可能会更好地理解什么是回调。

setTimeout(function () {
  console.log('Callback function')
}, 500)
console.log('This is called first!')

回调函数传给了setTimeout,setTimeout(callback, timeInMillisecons)所以在那个时间之后执行,另一个console.log在之前执行

这是一个愚蠢的例子,但当您向 API(例如 Facebook API)发出请求时,情况也是如此。您不知道请求需要多长时间才能响应,但您希望在那之后执行一些代码,并使用您获取的数据。所以你可以使用回调。