我是 firebase 的新手。我正在尝试使用将关联凭据发送到 firebase 的 node.js 服务器从实时数据库中检索数据,但在调用 once('value') 后,某些内容会被破坏:其返回的承诺永远不会得到解决,并且服务器会自行停止记录此消息:“进程已退出,代码为 3221226505”。
我写了以下代码:
async function testFirebase1(firebaseCredentialsObj, path) {
let firebase = require('firebase')
firebase.initializeApp(firebaseCredentialsObj);
var database = firebase.database();
var ref = database.ref(path);
console.log(ref.toString());
try {
// Attempt 1
var prom = await ref.once('value');
const data = prom.;
console.log('data ' + data)
// Attempt 2
prom.then((snapshot) => {
console.log('snapshot ' + snapshot)
}).catch((error) => { console.log(error)} )
} catch (error) {
console.log(error)
}
}
永远不会发现任何错误。 我也尝试以管理员身份获取数据,但我得到了相同的失败结果
async function testFirebase3(firebaseCredentials, serviceAccountKey, databaseURL, path) {
const admin=require('firebase-admin');
const serviceAccount = serviceAccountKey;
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: databaseURL
});
var db=admin.database();
var userRef=db.ref(path);
const prom = await userRef.once('value');
console.log(prom)
}
从once()方法返回的Promise保持悬而未决。这是它的日志:
[[PromiseStatus]]:'待处理' [[PromiseValue]]:未定义
服务器端应该以json格式获取数据库数据并将其发送给客户端。 为什么会出现这种情况?
根据您的代码,您将传统的 Promise 链接和
async
/await
语法混合在一起,这会导致您感到困惑。
注意:在下面的代码片段中,我使用了我在本答案的末尾描述的数据库查询编码风格。
SDK初始化testFirebase1
和
testFirebase3
中,您可以在函数中初始化默认的 Firebase 应用实例。如果您只调用任一函数一次,您不会遇到任何问题,但任何时候您再次调用它们时,它们总是会抛出一个错误,指出应用程序已经初始化。为了解决这个问题,您可以使用以下函数延迟加载这些库:
function lazyFirebase(options, name = undefined) {
const firebase = require('firebase');
// alternatively use the Promise-based version in an async function:
// const firebase = await import('firebase');
try {
firebase.app(name);
} catch (err) {
firebase.initializeApp(options, name);
}
return firebase;
}
function lazyFirebaseAdmin(options, name = undefined) {
const admin = require('firebase-admin');
// alternatively use the Promise-based version in an async function:
// const admin = await import('firebase-admin');
try {
admin.app(name);
} catch (err) {
const cred = options.credential;
if (typeof cred === "string") {
options.credential = admin.credential.cert(cred)
}
admin.initializeApp(options, name);
}
return admin;
}
重要提示: 上述两个函数都不会检查它们是否使用相同的 options
对象来初始化它们。它只是假设它们是相同的配置对象。纠正
testFirebase1
testFirebase1
中,您正在初始化默认的Firebase应用程序实例,然后开始从数据库获取数据的过程。因为您还没有从函数中的
ref.once('value')
返回承诺,所以调用者将得到一个
Promise<undefined>
,它会在数据库调用完成之前解析。
async function testFirebase1(firebaseCredentialsObj, path) {
let firebase = require('firebase')
// bug: throws error if initializeApp called more than once
firebase.initializeApp(firebaseCredentialsObj);
// bug: using `var` - use `const` or `let`
var database = firebase.database();
var ref = database.ref(path);
console.log(ref.toString());
try {
// Attempt 1
// bug: using `await` here, makes this a DataSnapshot not a Promise<DataSnapshot>
// hence `prom` should be `snapshot`
// bug: using `var` - use `const` or `let`
var prom = await ref.once('value');
// bug: syntax error, assuming this was meant to be `prom.val()`
const data = prom.;
console.log('data ' + data)
// Attempt 2
// bug: a `DataSnapshot` doesn't have a `then` or `catch` method
// bug: if `prom` was a `Promise`, you should return it here
prom
.then((snapshot) => {
console.log('snapshot ' + snapshot)
})
.catch((error) => {
console.log(error)
})
} catch (error) {
console.log(error)
}
}
纠正这些问题(并在处理 RTDB 查询时利用我的编码风格)可以得到:
async function testFirebase1(firebaseCredentialsObj, path) {
const firebase = lazyFirebase(firebaseCredentialsObj);
const snapshot = await firebase.database()
.ref(path)
.once('value');
// returns data at this location
return snapshot.val();
}
纠正testFirebase3
testFirebase3
中,您正在初始化默认的 Firebase 管理应用实例并正确等待来自数据库的数据。因为您尚未从数据库返回数据,所以调用者将得到一个
Promise<undefined>
,该值会在数据库调用完成时解析,但不包含包含的数据。
async function testFirebase3(firebaseCredentials, serviceAccountKey, databaseURL, path) {
const admin = require('firebase-admin');
// note: unnecessary line, either call `serviceAccountKey` `serviceAccount` or use `serviceAccountKey` as-is
const serviceAccount = serviceAccountKey;
// bug: throws error if initializeApp called more than once
// bug: `firebaseCredentials` is unused
// note: when initializing the *default* app's configuration, you
// should specify all options to prevent bugs when using
// `admin.messaging()`, `admin.auth()`, `admin.storage()`, etc
// as they all share the default app instance
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: databaseURL
});
// bug: using `var` - use `const` or `let`
var db=admin.database();
var userRef=db.ref(path);
// bug: using `await` here, makes this a DataSnapshot not a Promise<DataSnapshot>
// hence `prom` should be `snapshot`
const prom = await userRef.once('value');
// bug: logging a `DataSnapshot` object isn't useful because it
// doesn't serialize properly (it doesn't define `toString()`,
// so it will be logged as "[object Object]")
console.log(prom)
}
纠正这些问题(并在处理 RTDB 查询时利用我的编码风格)可以得到:
async function testFirebase3(firebaseCredentials, serviceAccountKey, databaseURL, path) {
const admin = lazyFirebaseAdmin({
...firebaseCredentials, // note: assuming `firebaseCredentials` is the complete app configuration,
credential: serviceAccountKey,
databaseURL: databaseURL
});
const snapshot = await admin.database()
.ref(path)
.once('value');
return snapshot.val();
}