尝试编写一个使用回调函数发送Facebook Messenger消息的函数 [英] Trying to write a function to use callbacks to send a Facebook Messenger message

查看:837
本文介绍了尝试编写一个使用回调函数发送Facebook Messenger消息的函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试编写一个函数以使用回调在Facebook Messenger中发送消息.我需要这样做,因为我在从数组发送文本时遇到问题.消息已发送,但发送顺序不正确.我想这是因为Node.js遍历元素的速度快于其发送文本的速度.在此处看到我的问题. /p>

所以现在我试图使用回调重写我的send函数,但徒劳地希望我可以以某种方式强制NodeJS在跳到下一个元素之前实际上等待它!

到目前为止,我有以下代码:

Main send function:

sendWithCallback: function(messageData, callback) {
    request({
            uri: 'https://graph.facebook.com/v2.6/me/messages',
            qs: {
                access_token: config.FB_PAGE_TOKEN
            },
            method: 'POST',
            json: messageData

        }, function (error, response, body) {
            if (!error && response.statusCode === 200) {
                let recipientId = body.recipient_id;
                console.log("Message sent to recipient '%s'", recipientId);
                callback(true);
            } else {
                console.error("Could not send message: ", response.statusCode, response.statusMessage, body.error)
                callback(false);
            }
        }
    );
},

Function for sending a "multi part" message (i.e. an Array of text):

sendMultipartMessage: function(recipientId, textArray) {
    let messageData, msgPart, msgLength, count = 0;
    msgLength = textArray.length;
    while (count < msgLength) {
        msgPart = textArray[count];
        messageData = {
            recipient: {
                id: recipientId
            },
            message: {
                text: msgPart
            }
        };
    }
    self.sendWithCallback(messageData, function(sent) {
        if (sent) {
            count++;
            console.log("Message part %s sent.", msgPart);
        }
        else {
            console.log("Couldn't send message");
        }
    });
},

在我的脑海中,此代码正常工作!它发送文本(从数组中获取),然后增加计数直到它等于messageLength.但实际上,它不这样做.相反,它只会进入无限循环(我看不到日志中发生的情况),然后使应用程序崩溃.

我在做什么错了?

解决方案

如果我们简化您的循环,则其本质就是这样:

let count = 0;
while (count < msgLength) {
  messageData = data;
}

您永远不会增加计数.

我认为您打算将while循环的self.sendWithCallback调用移入内部.但是,这仍然不会执行您想要的操作,并且将永远运行.即使它确实做了您想要的,它也无法解决按顺序发送消息的问题.

JavaScript的并发模型使用带有运行到完成."您可以使用sendWithCallback调用的类似request的方式将消息传递到事件队列.这只会将一条消息添加到队列中,但是直到当前运行的块完成后,该消息才会被处理.这意味着您的while循环实际上必须在您的任何请求开始运行之前完成.我们可以用setTimeout构建一个更简单的示例:

let count = 0;
while (count < 1) {
  setTimeout(() => {
    count++;
  }, 1000);
}
console.log('while loop completed');

在上面的while循环永远不会完成,因为count永远不会在同一块中递增(console.log永远不会被调用).它需要先完成,然后才能开始处理使用setTimeout创建的异步消息.


您实际上可以像这样重写它:

textArray.forEach(msgPart => self.sendWithCallback(msgPart, sent => {
  if (!sent) console.error('Could not send message');
});

但是,这不能保证消息的发送顺序,即使其中一条消息触发错误,它也将发送消息.如果要按顺序发送它们,则必须在上一条消息完成后在下一条消息的回调中递归调用sendWithCallback.可能看起来像这样:

let count = 0;
const sendMessage = (textArray, count) => {
  self.sendMessageWithCallback(textArray[count], sent => {
    count++;
    if (sent && count < textArray.length) {
      sendMessages(textArray, count);
    }
  });
}
sendMessages(textArray, 0);

如果您使用诺言和async/await,则可以将其编写为以下内容:

for (count = 0; count < msgLength; count++) {
  await self.sendMessageAsync(textArray[count]);
}

但是,这将需要对周围的代码进行更大程度的重写,并使用诸如request-promise之类的东西,而不仅仅是请求.

I'm trying to write a function to use callbacks to send a message in Facebook messenger. I need to do this because I'm having problems sending text from an array. The messages are sent, but not in the correct order. I THINK this is because Nodejs is looping over the elements faster than it can send the text. See my question about this here.

So now I am trying to rewrite my send functions using callbacks, in the vain hope that I can somehow FORCE NodeJS to actually WAIT before jumping to the next element!

So far I have the following code:

Main send function:

sendWithCallback: function(messageData, callback) {
    request({
            uri: 'https://graph.facebook.com/v2.6/me/messages',
            qs: {
                access_token: config.FB_PAGE_TOKEN
            },
            method: 'POST',
            json: messageData

        }, function (error, response, body) {
            if (!error && response.statusCode === 200) {
                let recipientId = body.recipient_id;
                console.log("Message sent to recipient '%s'", recipientId);
                callback(true);
            } else {
                console.error("Could not send message: ", response.statusCode, response.statusMessage, body.error)
                callback(false);
            }
        }
    );
},

Function for sending a "multi part" message (i.e. an Array of text):

sendMultipartMessage: function(recipientId, textArray) {
    let messageData, msgPart, msgLength, count = 0;
    msgLength = textArray.length;
    while (count < msgLength) {
        msgPart = textArray[count];
        messageData = {
            recipient: {
                id: recipientId
            },
            message: {
                text: msgPart
            }
        };
    }
    self.sendWithCallback(messageData, function(sent) {
        if (sent) {
            count++;
            console.log("Message part %s sent.", msgPart);
        }
        else {
            console.log("Couldn't send message");
        }
    });
},

In my head, this code works properly! It sends the text (taken from the array), then increments the count until it is equal to messageLength. But in reality it DOESN'T do that. Instead, it just goes into an infinite loop (which I can't see happening in my logs) and then crashes the app.

WHAT am I doing wrong?

解决方案

If we simplify your loop it essentially becomes this:

let count = 0;
while (count < msgLength) {
  messageData = data;
}

You never increment count.

I think that you intend to move the self.sendWithCallback call inside of the while loop. However, this still won't do what you want and will run forever. Even if it did do what you wanted, it wouldn't solve the problem of sending messages out in order.

JavaScript's concurrency model uses an event loop with "run-to-completion." You can pass messages to the event queue using something like request which you call by sendWithCallback. This only adds a message to the queue, but that message is not processed until the current running block completes. That means that your while loop actually has to complete before any of your requests start running. We can construct a simpler example with setTimeout:

let count = 0;
while (count < 1) {
  setTimeout(() => {
    count++;
  }, 1000);
}
console.log('while loop completed');

In the above the while loop never completes because count never gets incremented in the same block (console.log will never be called). It needs to complete before it can start processing the asynchronous messages you are creating with setTimeout.


You could actually just rewrite it like this:

textArray.forEach(msgPart => self.sendWithCallback(msgPart, sent => {
  if (!sent) console.error('Could not send message');
});

However this doesn't guarantee the order that the messages were sent and it will send messages even if one of the messages triggers an error. If you want to send them in order you will have to recursively call sendWithCallback within the callback for the next message once the previous one completes. That might look something like this:

let count = 0;
const sendMessage = (textArray, count) => {
  self.sendMessageWithCallback(textArray[count], sent => {
    count++;
    if (sent && count < textArray.length) {
      sendMessages(textArray, count);
    }
  });
}
sendMessages(textArray, 0);

If you were using promises and async/await you could write this much more simply as something like:

for (count = 0; count < msgLength; count++) {
  await self.sendMessageAsync(textArray[count]);
}

However this would require a larger rewrite of the surrounding code and using something like request-promise instead of just request.

这篇关于尝试编写一个使用回调函数发送Facebook Messenger消息的函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆