当前,我正在尝试获取数组中每个值的md5。本质上,我遍历每个值,然后对它进行哈希处理。
var crypto = require('crypto');
function userHash(userIDstring) {
return crypto.createHash('md5').update(userIDstring).digest('hex');
}
for (var userID in watching) {
refPromises.push(admin.database().ref('notifications/'+ userID).once('value', (snapshot) => {
if (snapshot.exists()) {
const userHashString = userHash(userID)
console.log(userHashString.toUpperCase() + "this is the hashed string")
if (userHashString.toUpperCase() === poster){
return console.log("this is the poster")
}
else {
..
}
}
else {
return null
}
})
)}
但是,这导致两个问题。首先是我收到错误警告“不要在循环内创建函数”。第二个问题是散列都返回相同的值。即使每个userID
都是唯一的,userHashString仍在控制台日志中为每个用户打印相同的值,就好像它只是使用第一个userID一样,为其获取哈希值,然后每次都将其打印出来
更新最新:
exports.sendNotificationForPost = functions.firestore
.document('posts/{posts}').onCreate((snap, context) => {
const value = snap.data()
const watching = value.watchedBy
const poster = value.poster
const postContentNotification = value.post
const refPromises = []
var crypto = require('crypto');
function userHash(userIDstring) {
return crypto.createHash('md5').update(userIDstring).digest('hex');
}
for (let userID in watching) {
refPromises.push(admin.database().ref('notifications/'+ userID).once('value', (snapshot) => {
if (snapshot.exists()) {
const userHashString = userHash(userID)
if (userHashString.toUpperCase() === poster){
return null
}
else {
const payload = {
notification: {
title: "Someone posted something!",
body: postContentNotification,
sound: 'default'
}
};
return admin.messaging().sendToDevice(snapshot.val(), payload)
}
}
else {
return null
}
})
)}
return Promise.all(refPromises);
});
答案 0 :(得分:1)
这些不是两个问题:您得到的警告正在试图帮助您解决发现的第二个问题。
问题是:在Javascript中,只有函数创建单独的作用域-在循环中定义的每个函数都使用相同的作用域。这意味着他们没有得到自己的相关循环变量副本,而是共享一个引用(在解析第一个诺言时,它等于数组的最后一个元素)。
只需将for
替换为.forEach
。
答案 1 :(得分:1)
您在这里遇到了几个问题。首先,您在循环内有一个非阻塞的异步操作。您需要完全理解这意味着什么。您的循环运行完成,开始了一系列非阻塞的异步操作。然后,当循环完成时,您的异步操作将一一完成。这就是为什么循环变量userID
位于错误的值的原因。当所有异步回调都被调用时,它在终端值上。
您可以在此处看到有关循环变量问题的讨论,其中包含一些用于解决该问题的选项:
Asynchronous Process inside a javascript for loop
第二,您还需要一种方法来知道何时完成所有异步操作。就像您派出了20羽信鸽,不知道它们何时会带回您一些消息(以任意顺序),因此您需要一种方法来知道它们何时都回来了。
要知道何时完成所有异步操作,可以使用多种方法。 “现代设计”和Java语言的未来将是使用Promise来代表您的异步操作,并使用Promise.all()
来跟踪它们,使结果保持顺序,在完成所有操作时通知您并传播任何可能发生的错误。
这是您代码的清理版本:
const crypto = require('crypto');
exports.sendNotificationForPost = functions.firestore.document('posts/{posts}').onCreate((snap, context) => {
const value = snap.data();
const watching = value.watchedBy;
const poster = value.poster;
const postContentNotification = value.post;
function userHash(userIDstring) {
return crypto.createHash('md5').update(userIDstring).digest('hex');
}
return Promise.all(Object.keys(watching).map(userID => {
return admin.database().ref('notifications/' + userID).once('value').then(snapshot => {
if (snapshot.exists()) {
const userHashString = userHash(userID);
if (userHashString.toUpperCase() === poster) {
// user is same as poster, don't send to them
return {response: null, user: userID, poster: true};
} else {
const payload = {
notification: {
title: "Someone posted something!",
body: postContentNotification,
sound: 'default'
}
};
return admin.messaging().sendToDevice(snapshot.val(), payload).then(response => {
return {response, user: userID};
}).catch(err => {
console.log("err in sendToDevice", err);
// if you want further processing to stop if there's a sendToDevice error, then
// uncomment the throw err line and remove the lines after it.
// Otherwise, the error is logged and returned, but then ignored
// so other processing continues
// throw err
// when return value is an object with err property, caller can see
// that that particular sendToDevice failed, can see the userID and the error
return {err, user: userID};
});
}
} else {
return {response: null, user: userID};
}
});
}));
});
更改:
require()
移出循环。没有理由多次调用它。.map()
来收集Promise.all()
的诺言数组。Object.keys()
从对象键中获取一个用户ID数组,这样我们就可以在其上使用.map()
。.then()
与.once()
一起使用。sendToDevice()
错误。Promise.all()
跟踪所有承诺的完成时间