在 forEach 之后使用 Promise.all() 渲染 NodeJS 页面之前等待 Firebase 数据加载

Posted

技术标签:

【中文标题】在 forEach 之后使用 Promise.all() 渲染 NodeJS 页面之前等待 Firebase 数据加载【英文标题】:Wait for Firebase data to load before rendering NodeJS page after forEach with Promise.all() 【发布时间】:2017-05-13 04:53:14 【问题描述】:

我正在尝试创建一个从 Firebase 加载多个数据集的页面,然后将它们传递给 NodeJS 呈现的页面。我会很感激一些帮助,以确保在 forEach 迭代之后发生这种情况;也就是说,我不确定如何让 Firebase forEach 迭代成为我的承诺的一部分。

非常感谢!

router.get('/', function(req, res, next) 

    var getBrands = brandRef.once('value').then(function(snapshot)
        var brands = [];

        snapshot.forEach(function(childSnapshot)
            console.log(childSnapshot.val()['name']);
            brands.push('name' : childSnapshot.val()['name'] );
        );

        return brands;
    );
    var getStores = storeRef.once('value').then(function(snapshot)
        var stores = [];

        snapshot.forEach(function(childSnapshot)
            stores.push('name' : childSnapshot.val()['name'] );
        );

        return stores;
    );
    var getProducts = productRef.once('value').then(function(snapshot)
        var products = [];

        snapshot.forEach(function(childSnapshot)
            products.push('name' : childSnapshot.val()['name'] );
        );

        return products;
    );

    console.log(brands, stores, products);
    Promise.all([getBrands, getStores, getProducts]).then(function(results)

        res.render('index',  title: 'MStore Demo Portal', stores: results[0], brands: results[1], products: results[2] );
    );
);

【问题讨论】:

看我的回答——你可以把这段代码从后端移动到前端,你所做的就是合并数据库中的结果。 那些是snapshots 数组,还是自定义(甚至是异步)forEach 方法? @Bergi,这是用于快照的内置 Firebase forEach 函数。 如果是异步的,怎么知道什么时候完成? 【参考方案1】:

Firebase 设计为无服务器架构。从长远来看,您不需要标准的 RESTFul Node.js API 服务器。您只需要 Lambda 工作人员。请看:https://github.com/firebase/firebase-queue

将工作放入队列中,工作人员将接手工作并更新 Firebase。当 Firebase 更新时,它会向您的前端发送消息。这一切都是异步的,应该适用于几乎任何应用程序。

拥有 API 服务器也没有什么问题,但实际上并不需要。除非您有充分的理由拥有我认为的 Express API 服务器,否则您可以放弃它。

看起来您对这段代码所做的只是从数据库中获取值,您可以使用前端而不是 API 服务器来执行此操作,并在前端合并结果,这样做会更好事情就是这样。

从字面上看,只需在此处获取 Express 中的代码,并将其移动到您的前端应用程序中:)

【讨论】:

Literally, just take the code that's in Express here, and move it to your front-end app 这实际上是不够的,除了将问题中的代码移动到前端应用程序之外,还有很多工作要做(假设前端应用程序是基于 javascript 的很好假设,它仍然是一个假设) @JaromandaX 我支持我的 cmets/answer,如果您删除 Express 路由代码行,您基本上可以解除代码并将其放在前端。我是一名后端开发人员,但 Firebase 被设计成一个非常依赖客户端的架构。你直接回答了这个问题,但我想就更大的图景提出一点看法。 Firebase 被称为“无服务器”架构是有原因的。想想这意味着什么。 只是看着firebase-queue,似乎涉及很多设置(虽然我可能是错的) - 我没有质疑你的答案,我正在尝试从中学习:p @JaromandaX 我是个老派,我不喜欢闪亮的东西。然而 Firebase 队列很有意义,而 Lambda 架构才是真正的交易。一般来说,我喜欢遵循 ​​KISS,在这种情况下,标准的 RESTful API 会看起来是 KISS 方式。但是,一旦您对 Lambda 和 Firebase 队列进行了一些工作,您就会看到好处。 Firebase-Queue 是使用 Firebase DB 进行后端开发的规范方式。 RESTful API 服务器不是规范的方式。 此外,TMK、Firebase 也可以启动您的应用。您确实不需要需要 API 服务器来提供 index.html。如果这个问题在你的脑海中。当我第一次开始使用 Firebase 时,我认为至少您需要自己的服务器来发送索引页面,然后其他所有内容都将是对 Firebase 的“JSON 调用”。但我认为 Firebase 也可以提供您的 html 文件。【参考方案2】:

您的代码看起来 99% 正常

router.get('/', function(req, res, next) 
    var getBrands = ...;
    var getStores = ...;
    var getProducts = ...;

到目前为止一切顺利(甚至没有复制代码,因为它是正确的

    console.log(brands, stores, products);

品牌、商店和产品在 .then 回调中声明,因此无论如何,此时它们始终是未定义的

    Promise.all([getBrands, getStores, getProducts]).then(function(results)

        res.render('index',  title: 'MStore Demo Portal', stores: results[0], brands: results[1], products: results[2] );
    );
);

上面唯一的“问题”是,由于您在 Promsie.all 中订购了getBrands, getStores, getProducts,结果将是brands, stores, products

但是,您似乎认为(基于索引)结果将是 stores, brands, products - 在代码中交换索引 0 和 1,或者调用

Promise.all([getStores, getBrands, getProducts]).then

提示,如果您使用的是足够新的 node.js,您可以执行以下操作

Promise.all([getStores, getBrands, getProducts]).then(([stores, brands, products]) =>
    res.render('index',  title: 'MStore Demo Portal', stores, brands, products )
);

【讨论】:

这是一个编码方案,但我认为这段代码不需要在API服务器上,只需将这段代码移到前端! 这是问题的“解决方案”-答案的唯一真实部分是 console.log 不会显示任何有用的信息,尽管 0 1 换位,代码确实是正确的 - 完全不知道引入 firebase-queue 是如何回答 OP 的问题的 非常感谢您的帮助和最后的速记,Jaromanda!我不敢相信我没有发现这个问题。

以上是关于在 forEach 之后使用 Promise.all() 渲染 NodeJS 页面之前等待 Firebase 数据加载的主要内容,如果未能解决你的问题,请参考以下文章

在 forEach 之后使用 Promise.all() 渲染 NodeJS 页面之前等待 Firebase 数据加载

如何在 ForEach 循环之后保留对象变量更改。 Javascript

在 int 值之后对 ForEach 中的 FireStore 数据进行排序

在ajax之后重新加载laravel foreach

我应该在每个 foreach 语句之后取消设置 `$key` 和 `$value` 吗?

Knockout ViewModel 在 ajax 之后被更新,但我的 foreach 没有被触发