Firebase JS:为什么以及何时取消订阅 onAuthStateChanged
Firebase JS: Why and When to unsubscribe onAuthStateChanged
我在一个奇怪的网站上工作,我只需要将表单发送到 firestore 并将 pdf 文件保存到 firestore。
甚至没有 运行 任何服务器端代码,只有 html 和最终客户端上的 JS。
我的组织只会给 运行 html、CSS 和 JS 一个 apache 服务器路径。
稍后我需要阅读,但我是唯一具有读取权限的用户,所以这没什么大不了的,因为我会 运行 在我的 node.js CLI 上本地阅读。
但我期待着让我的代码尽可能安全和高效,尽管我有 60% 的时间都不知道自己在做什么。
在线阅读文档和代码后,我意识到我在执行 onAuthStateChanged() 时并没有执行 unsubscribe()。
通过搜索 JS 上的内存泄漏,我发现有人说如果我想在内存中保留一些东西,那么我不应该取消订阅。但是正如我所说,我不知道我在做什么。
这是我的一些 .js 和我的 login.html
我担心 4 件事,我来了:
- 我是否应该在 登出 onAuthStateChanged 结束后取消订阅()?如果有,在哪里?
- 是否可以在 window.onload 中设置所有这些代码?
- 我是否应该将此代码拆分为模块以便我可以重新使用 initializeApp() 和其他重复代码,或者不推荐这样做,因为我正在使用 CDN 导入 firebase 模块而不是使用导入语句。
- 我是否应该在 html 的每个页面上执行 initializeApp()?或者在登录时执行一次并强制用户通过 vanilla JS 登录将是可行的方法?
window.onload = () => {
//Config and init fb
var firebaseConfig = {
//...my config
};
if (!firebase.apps.length) {
firebase.initializeApp(firebaseConfig)
}
const auth = firebase.auth();
const provider = new firebase.auth.GoogleAuthProvider();
//Get elements
const signInBtn = document.getElementById("log-in-btn");
//Listeners
signInBtn.onclick = () => auth.signInWithPopup(provider);
//Listeners require user
//sign-in-out
auth.onAuthStateChanged(user => {
if (user) {
// signed in
if (!user.email.includes('@mydomain.com')) {
auth.signOut();
//maybe delete the user, haven't test it
alert('Porfavor utilice su correo institucional');
} else {
window.location.replace('dashboard.html');
}
} else {
// not signed in you will always end up here
}
});
}
html 都是这样的,但我每个 html 都有一个 JS 文件,每个 JS 配置和初始化 firebase。
<head>
<meta charset="UTF-8">
<title>Login </title>
<!--Project CSS-->
<!--Boostrap 5-->
<!--Firebase Modules-->
<script src="https://www.gstatic.com/firebasejs/8.10.0/firebase-app.js"></script>
<script src="https://www.gstatic.com/firebasejs/8.10.0/firebase-firestore.js"></script>
<script src="https://www.gstatic.com/firebasejs/8.10.0/firebase-auth.js"></script>
<script src="https://www.gstatic.com/firebasejs/8.10.0/firebase-storage.js"></script>
<!--Proyect Modules-->
<script src="js/login.js" defer></script>
</head>
稍后在我的仪表板中这是我的方法
window.onload = () => {
var firebaseConfig = {
//my config
};
if (!firebase.apps.length) {
firebase.initializeApp(firebaseConfig)
}
const auth = firebase.auth();
const provider = new firebase.auth.GoogleAuthProvider();
//Get elements
const signedIn = document.getElementById("toggle-w-log-in");
const signedOff = document.getElementById("toggle-w-log-off");
const signInBtn = document.getElementById("log-in-btn");
const signOutBtn = document.getElementById("log-off-btn");
const uname = document.getElementById("userName");
const userDetails = document.getElementById("userDetails");
//Events / Listeners
signOutBtn.onclick = () => {
auth.signOut();
window.location.replace("login.html");
};
//Events / Listeners that require user
//sign-in-out
auth.onAuthStateChanged(user => {
if (user) {
// signed in
signedIn.hidden = false;
signedOff.hidden = true;
userDetails.innerHTML = `<b>Sesión iniciada como ${user.displayName}</b>`;
var contentImgUser = document.getElementById("img-Us");
contentImgUser.setAttribute("src", user.photoURL);
} else {
// not signed in
signedIn.hidden = true;
signedOff.hidden = false;
userDetails.innerHTML = '';
window.location.replace("login.html");
}
});
}
最后一个百万美元的问题:我是否为我的表格编写了这段代码?
window.onload = () => {
var firebaseConfig = {
//my config
};
if (!firebase.apps.length) {
firebase.initializeApp(firebaseConfig)
}
const auth = firebase.auth();
const provider = new firebase.auth.GoogleAuthProvider();
//Get elements from dom by id
//Events / Listeners
//sign-in-out
signOutBtn.onclick = () => {
auth.signOut();
window.location.replace("login.html");
};
auth.onAuthStateChanged(user => {
if (user) {
// signed in
signedIn.hidden = false;
signedOff.hidden = true;
//display the userDetails
//display user name in the username field
uname.value = user.displayName;
} else {
// not signed in
signedIn.hidden = true;
signedOff.hidden = false;
userDetails.innerHTML = '';
window.location.replace("login.html");
}
});
//save file to Firestorage then save doc to Firestore
//finally set a cooldown on the button
auth.onAuthStateChanged(user => {
saveBtn.addEventListener("click", (event) => {
event.preventDefault();
//check my required files
if (requiredFields) {
saveBtn.disabled = true;
//some logic with my progressbar
var metadata = {
contentType: 'application/pdf'
};
const files = document.getElementById("myfile").files;
var storageRef = firebase.storage().ref();
let file = files[0];
// Upload file and metadata to the object 'pdf/filename.pdf'
// Listen for state changes, errors, and completion of the upload.
uploadTask.on(firebase.storage.TaskEvent.STATE_CHANGED,
(snapshot) => {
// Get task progress, including the number of bytes uploaded and the total number of bytes to be uploaded
//some logic with the progress to fill my progressbar
switch (snapshot.state) {
case firebase.storage.TaskState.PAUSED:
break;
case firebase.storage.TaskState.RUNNING:
break;
}
},
(error) => {
switch (error.code) {
case 'storage/unauthorized':
break;
case 'storage/canceled':
break;
case 'storage/unknown':
break;
}
},
() => {
// Upload completed successfully, now we can get the download URL
uploadTask.snapshot.ref.getDownloadURL().then((downloadURL) => {
const db = firebase.firestore().collection('mycollections');
const userUid = user.uid;
const timestamp = new Date().getTime();
try {
db.add({
refEvi: downloadURL,
userUid: userUid,
//all my fields
}).then((docRef) => {
artRes.innerHTML = "<b>Registro guardado con la referencia: </b>" + docRef.id;
});
} catch (error) {
console.log(error);
artRes.innerHTML = "<b>Problema al guardar registro en la base de datos. </b>" + error;
} finally {
//a timer to enable my button a few secs after everything is done
}
});
}
);
}
});
});
}
是的,我只是用注释替换了一些代码,使post可读。
我的 js 中有什么地方我应该取消订阅 onAuthStateChanged 吗?
订阅身份验证状态取决于您的用例。
- 如果您想以反应方式开发您的系统,也就是说,您的 UI 会自行更改,因为它订阅了 auth 状态(没有重新加载或重定向)。那么你应该永不退订授权状态。
- 相反的情况(您不想订阅),您可以监听身份验证状态更改事件(提交登录表单后来自 Firebase 的响应)并对 UI 进行适当的更改。在这种情况下,您应该在每次 页面加载时检查身份验证状态。这样,您可以重新加载或重定向,因为您将检查身份验证状态。当然,您还必须知道用户何时注销。
我在一个奇怪的网站上工作,我只需要将表单发送到 firestore 并将 pdf 文件保存到 firestore。 甚至没有 运行 任何服务器端代码,只有 html 和最终客户端上的 JS。 我的组织只会给 运行 html、CSS 和 JS 一个 apache 服务器路径。 稍后我需要阅读,但我是唯一具有读取权限的用户,所以这没什么大不了的,因为我会 运行 在我的 node.js CLI 上本地阅读。
但我期待着让我的代码尽可能安全和高效,尽管我有 60% 的时间都不知道自己在做什么。
在线阅读文档和代码后,我意识到我在执行 onAuthStateChanged() 时并没有执行 unsubscribe()。 通过搜索 JS 上的内存泄漏,我发现有人说如果我想在内存中保留一些东西,那么我不应该取消订阅。但是正如我所说,我不知道我在做什么。
这是我的一些 .js 和我的 login.html 我担心 4 件事,我来了:
- 我是否应该在 登出 onAuthStateChanged 结束后取消订阅()?如果有,在哪里?
- 是否可以在 window.onload 中设置所有这些代码?
- 我是否应该将此代码拆分为模块以便我可以重新使用 initializeApp() 和其他重复代码,或者不推荐这样做,因为我正在使用 CDN 导入 firebase 模块而不是使用导入语句。
- 我是否应该在 html 的每个页面上执行 initializeApp()?或者在登录时执行一次并强制用户通过 vanilla JS 登录将是可行的方法?
window.onload = () => { //Config and init fb var firebaseConfig = { //...my config }; if (!firebase.apps.length) { firebase.initializeApp(firebaseConfig) } const auth = firebase.auth(); const provider = new firebase.auth.GoogleAuthProvider(); //Get elements const signInBtn = document.getElementById("log-in-btn"); //Listeners signInBtn.onclick = () => auth.signInWithPopup(provider); //Listeners require user //sign-in-out auth.onAuthStateChanged(user => { if (user) { // signed in if (!user.email.includes('@mydomain.com')) { auth.signOut(); //maybe delete the user, haven't test it alert('Porfavor utilice su correo institucional'); } else { window.location.replace('dashboard.html'); } } else { // not signed in you will always end up here } }); }
html 都是这样的,但我每个 html 都有一个 JS 文件,每个 JS 配置和初始化 firebase。
<head> <meta charset="UTF-8"> <title>Login </title> <!--Project CSS--> <!--Boostrap 5--> <!--Firebase Modules--> <script src="https://www.gstatic.com/firebasejs/8.10.0/firebase-app.js"></script> <script src="https://www.gstatic.com/firebasejs/8.10.0/firebase-firestore.js"></script> <script src="https://www.gstatic.com/firebasejs/8.10.0/firebase-auth.js"></script> <script src="https://www.gstatic.com/firebasejs/8.10.0/firebase-storage.js"></script> <!--Proyect Modules--> <script src="js/login.js" defer></script> </head>
稍后在我的仪表板中这是我的方法
window.onload = () => { var firebaseConfig = { //my config }; if (!firebase.apps.length) { firebase.initializeApp(firebaseConfig) } const auth = firebase.auth(); const provider = new firebase.auth.GoogleAuthProvider(); //Get elements const signedIn = document.getElementById("toggle-w-log-in"); const signedOff = document.getElementById("toggle-w-log-off"); const signInBtn = document.getElementById("log-in-btn"); const signOutBtn = document.getElementById("log-off-btn"); const uname = document.getElementById("userName"); const userDetails = document.getElementById("userDetails"); //Events / Listeners signOutBtn.onclick = () => { auth.signOut(); window.location.replace("login.html"); }; //Events / Listeners that require user //sign-in-out auth.onAuthStateChanged(user => { if (user) { // signed in signedIn.hidden = false; signedOff.hidden = true; userDetails.innerHTML = `<b>Sesión iniciada como ${user.displayName}</b>`; var contentImgUser = document.getElementById("img-Us"); contentImgUser.setAttribute("src", user.photoURL); } else { // not signed in signedIn.hidden = true; signedOff.hidden = false; userDetails.innerHTML = ''; window.location.replace("login.html"); } }); }
最后一个百万美元的问题:我是否为我的表格编写了这段代码?
window.onload = () => { var firebaseConfig = { //my config }; if (!firebase.apps.length) { firebase.initializeApp(firebaseConfig) } const auth = firebase.auth(); const provider = new firebase.auth.GoogleAuthProvider(); //Get elements from dom by id //Events / Listeners //sign-in-out signOutBtn.onclick = () => { auth.signOut(); window.location.replace("login.html"); }; auth.onAuthStateChanged(user => { if (user) { // signed in signedIn.hidden = false; signedOff.hidden = true; //display the userDetails //display user name in the username field uname.value = user.displayName; } else { // not signed in signedIn.hidden = true; signedOff.hidden = false; userDetails.innerHTML = ''; window.location.replace("login.html"); } }); //save file to Firestorage then save doc to Firestore //finally set a cooldown on the button auth.onAuthStateChanged(user => { saveBtn.addEventListener("click", (event) => { event.preventDefault(); //check my required files if (requiredFields) { saveBtn.disabled = true; //some logic with my progressbar var metadata = { contentType: 'application/pdf' }; const files = document.getElementById("myfile").files; var storageRef = firebase.storage().ref(); let file = files[0]; // Upload file and metadata to the object 'pdf/filename.pdf' // Listen for state changes, errors, and completion of the upload. uploadTask.on(firebase.storage.TaskEvent.STATE_CHANGED, (snapshot) => { // Get task progress, including the number of bytes uploaded and the total number of bytes to be uploaded //some logic with the progress to fill my progressbar switch (snapshot.state) { case firebase.storage.TaskState.PAUSED: break; case firebase.storage.TaskState.RUNNING: break; } }, (error) => { switch (error.code) { case 'storage/unauthorized': break; case 'storage/canceled': break; case 'storage/unknown': break; } }, () => { // Upload completed successfully, now we can get the download URL uploadTask.snapshot.ref.getDownloadURL().then((downloadURL) => { const db = firebase.firestore().collection('mycollections'); const userUid = user.uid; const timestamp = new Date().getTime(); try { db.add({ refEvi: downloadURL, userUid: userUid, //all my fields }).then((docRef) => { artRes.innerHTML = "<b>Registro guardado con la referencia: </b>" + docRef.id; }); } catch (error) { console.log(error); artRes.innerHTML = "<b>Problema al guardar registro en la base de datos. </b>" + error; } finally { //a timer to enable my button a few secs after everything is done } }); } ); } }); }); }
是的,我只是用注释替换了一些代码,使post可读。 我的 js 中有什么地方我应该取消订阅 onAuthStateChanged 吗?
订阅身份验证状态取决于您的用例。
- 如果您想以反应方式开发您的系统,也就是说,您的 UI 会自行更改,因为它订阅了 auth 状态(没有重新加载或重定向)。那么你应该永不退订授权状态。
- 相反的情况(您不想订阅),您可以监听身份验证状态更改事件(提交登录表单后来自 Firebase 的响应)并对 UI 进行适当的更改。在这种情况下,您应该在每次 页面加载时检查身份验证状态。这样,您可以重新加载或重定向,因为您将检查身份验证状态。当然,您还必须知道用户何时注销。