Javascript Node.js是否使用以前的值进行循环?
目前,我正在尝试获取数组中每个值的md5。本质上,我在每个值上循环,然后散列它,就像这样Javascript Node.js是否使用以前的值进行循环?,javascript,node.js,Javascript,Node.js,目前,我正在尝试获取数组中每个值的md5。本质上,我在每个值上循环,然后散列它,就像这样 var crypto = require('crypto'); function userHash(userIDstring) { return crypto.createHash('md5').update(userIDstring).digest('hex'); } for (var userID in watching) { refPromises.push(admin.
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);
});
这不是两个问题:你得到的警告是试图帮助你解决你注意到的第二个问题 问题是:在Javascript中,只有函数创建单独的作用域——在循环中定义的每个函数——使用相同的作用域。这意味着它们没有得到自己的相关循环变量的副本,它们共享一个引用(当第一个承诺得到解决时,它将等于数组的最后一个元素)
只需将的替换为。首先,在循环中有一个非阻塞异步操作。你需要完全理解这意味着什么。您的循环运行到结束,开始一系列非阻塞的异步操作。然后,当循环完成时,异步操作一个接一个地完成。这就是为什么循环变量
userID
的值不正确。当调用所有异步回调时,它位于终端值上
您可以在这里看到关于循环变量问题的讨论,其中有几个选项用于解决该问题:
其次,您还需要一种方法来知道所有异步操作何时完成。这有点像你发送了20只信鸽,却不知道它们什么时候都会给你带回一些信息(以任意顺序),所以你需要一种方法来知道它们什么时候都回来了
要知道所有异步操作何时完成,有许多不同的方法。“现代设计”和Javascript语言的未来将是使用承诺来表示异步操作,并使用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()
与一起使用
sendToDevice()
错误Promise.all()
跟踪所有承诺何时完成我把它改成了forEach,除了refpromises.push实际上是在等待信鸽吗?因为它等待承诺,正确吗?@RaimKhalil-
forEach()
将解决您的循环迭代器问题,因为它为循环的每次调用生成唯一的函数调用和函数参数。admin.database().ref('notifications/'+userID).once('value',(snapshot)=>{})返回什么?它是否回报了承诺?通常,在同时支持回调和承诺的现代接口中,如果您像现在这样传递回调,它也不会返回承诺。对不起,我没有包括承诺的返回。这样做正确吗?(正如我更新的回答中所说)很抱歉我的困惑,我对node.js非常陌生。我不太确定它返回什么——在另一个问题中,有人回答说,你们都在向once()传递回调,并使用它返回的承诺。你应该选择其中一个,最好只是使用它的承诺。
@RaimKhalil-返回承诺。全部(refPromises)如果refPromises
实际上是一个承诺数组,那么code>是正确的想法,但我不认为这是因为您正在传递回调。我将在我的答案中添加一些内容,以便稍后向您展示。然后调用者必须对调用它的返回值使用.Then()
。监视变量的数据类型是什么。它是一个用户ID数组吗?或者是一个以userID作为属性或值的对象?它是一个userID数组,那么for(var userID in watching)
也不会迭代数组。迭代对象上的属性,而不是数组元素。切勿使用for/in
迭代数组元素。从不在modern node.js中,使用for/of
。如果您使用的是较新版本的node,您应该能够使用let
而不是for
循环中的var
。@MarkMeyer.forEach对对象不起作用,是吗?那么用let替换var就可以解决这个问题了?