我试图编写一个函数来使用回调来在Facebook Messenger中发送消息。我需要这样做,因为我在从数组发送文本时遇到问题。邮件将被发送,但顺序不正确。我认为这是因为Nodejs比传输文本更快地循环元素。请参阅我关于此here的问题。
所以现在我正在尝试使用回调重写我的发送函数,徒劳地希望我能以某种方式强迫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。但实际上,DOESN&#T; T会这样做。相反,它只是进入一个无限循环(我无法在我的日志中看到)然后崩溃应用程序。
我做错了什么?
答案 0 :(得分:0)
如果我们简化你的循环,它基本上就变成了这个:
let count = 0;
while (count < msgLength) {
messageData = data;
}
你永远不会增加数量。
我认为您打算移动while循环中的self.sendWithCallback
调用 。然而,这仍然不会做你想要的,并将永远运行。即使它确实按照您的意愿行事,也无法解决按顺序发送消息的问题。
JavaScript's concurrency model使用带有&#34;运行到完成的事件循环。&#34;您可以使用request
调用sendWithCallback
之类的内容将消息传递到事件队列。这只会向队列添加一条消息,但在当前正在运行的块完成之前不会处理该消息。这意味着你的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]);
}
然而,这需要对周围代码进行更大的重写,并使用诸如请求承诺之类的东西,而不仅仅是请求。