当一个页面有多个数据块的时候,后台一般是怎么写的? Nodejs 相关实现思路

当一个页面有多个数据块的时候,后台一般是怎么写的? Nodejs 相关实现思路

是挨个嵌套调用吗,然后在最内层render 模板吗?

6 回复

当一个页面包含多个数据块时,后台处理通常会涉及到多个异步操作,这些操作可能包括数据库查询、外部API调用等。在Node.js中,可以使用Promise或async/await来管理这些异步操作,确保所有数据都准备好后再渲染模板。

以下是一个简单的示例,展示如何使用Node.js和Express框架来处理这种情况:

  1. 安装必要的依赖

    npm install express
    
  2. 创建服务器文件(例如app.js

    const express = require('express');
    const app = express();
    const port = 3000;
    
    // 假设我们有两个数据源
    const fetchDataBlockA = async () => {
        return new Promise((resolve) => {
            setTimeout(() => {
                resolve({ blockA: 'Data from Block A' });
            }, 500);
        });
    };
    
    const fetchDataBlockB = async () => {
        return new Promise((resolve) => {
            setTimeout(() => {
                resolve({ blockB: 'Data from Block B' });
            }, 300);
        });
    };
    
    // 渲染模板的函数
    const renderTemplate = (data) => {
        const template = `
        <html>
            <head><title>Data Blocks</title></head>
            <body>
                <h1>Data Block A</h1>
                <p>${data.blockA}</p>
                <h1>Data Block B</h1>
                <p>${data.blockB}</p>
            </body>
        </html>
        `;
        return template;
    };
    
    app.get('/', async (req, res) => {
        try {
            // 同时获取两个数据块
            const [dataA, dataB] = await Promise.all([fetchDataBlockA(), fetchDataBlockB()]);
            // 合并数据
            const combinedData = { ...dataA, ...dataB };
            // 渲染模板
            const htmlContent = renderTemplate(combinedData);
            res.send(htmlContent);
        } catch (error) {
            console.error(error);
            res.status(500).send('Internal Server Error');
        }
    });
    
    app.listen(port, () => {
        console.log(`Server running at http://localhost:${port}`);
    });
    

解释

  1. 数据获取

    • fetchDataBlockAfetchDataBlockB 是两个异步函数,分别模拟从不同数据源获取数据的过程。
    • 使用 setTimeout 来模拟异步操作,实际应用中可能会涉及数据库查询、外部API调用等。
  2. 模板渲染

    • renderTemplate 函数用于将获取到的数据合并到HTML模板中。
  3. 路由处理

    • 在根路径 / 的路由处理器中,使用 Promise.all 同时获取两个数据块,并在数据准备好后调用 renderTemplate 函数生成最终的HTML内容。
    • Promise.all 确保所有异步操作完成后才继续执行后续逻辑,避免了嵌套回调带来的复杂性。

这种方式不仅提高了代码的可读性和可维护性,还使得异步操作更加高效和易于管理。


多个数据块之间有依赖吗?

平行关系的多个数据块,再模板里单独render就行。

比如这个贴子的页面,左面是贴子,右面是用户信息, 两者没有依赖关系,你说的单独render是这样吗?

 var post = require('../models/post.js');

post.findOne({_id:xxx},function(err,post)){

res.render(‘topic’,{post:post});

}

var user = require(’…/models/user.js’);

post.findOne({_id:xxx},function(err,info)){

res.render(‘topic’,{info:info});

}

肯定不是这样的啊,如果是ejs模板,你可以用include ,你要等到把数据都拿到了才调用render,或者前头异步加载

这个问题抽象出来就是nodejs的异步流控制(Asynchronous Control Flow),楼主所关心是属于其中的并行流。成熟的解决方案有async,step,promise之类的,自行google。顺带一提,cnodejs的社区论坛是用eventproxy。 如果不想引入额外的模块,自行折腾一个也不难。论坛这篇文章JS异步流程控制(序列模式、并发模式、有限并发模式)应该对你有所启发。考虑伸手党,附上我自己曾经用过一种方法的:

function parallel(limit, done) {
  if (typeof limit == 'function') {
    done = limit, limit = 0;
  }
  var jobs = [], results = [], i = 0;
  var dones = 0; //total number of finished job
  function next(n) {
    if (dones === jobs.length) done(results);
    for (var j = 0; j < n && i < jobs.length; j++, i++) {
      jobs[i](function (pos) {
        dones++;
        results[pos] = [].slice.call(arguments, 1);
        next(1);
      }.bind(null, i));
    };
  }
  process.nextTick(function () {
    //run next <limit> jobs. if limit=0, run all the jobs
    next(limit || jobs.length);
  });
  return {
    do : function (job) { jobs.push(job); return this; }
  };
}
var post, info;
var task = parallel(function (results) {
  res.render('topic', { post: post, info: info });
});
task.do(function (done) {
  post.findOne({ _id: xx }, function (err, _post) {
    post = _post; done();
  });
});
task.do(function (done) {
  post.findOne({ _id: xx }, function (err, _info) {
    info = _info; done();
  });
});

在Node.js中处理多数据块的情况时,通常不会采用嵌套调用的方式来获取所有数据,而是使用异步编程来并行或按需获取数据。这可以通过Promise、async/await或者回调函数来实现。这里提供一种较为简洁的方法,即利用Promise.all来并行处理多个异步操作,并且在所有数据获取完成后统一渲染模板。

实现思路

  1. 定义获取数据的函数:为每个数据块定义一个独立的函数,这些函数负责与数据库交互或其他服务进行通信以获取特定的数据。
  2. 使用Promise.all并行处理:使用Promise.all来并行执行所有数据获取函数。这样可以提高效率,尤其是在数据获取之间没有依赖关系的情况下。
  3. 渲染模板:在所有数据获取完成之后,将所有数据传递给模板引擎进行渲染。

示例代码

假设我们有一个Express应用,并且需要从两个不同的数据源获取数据(比如一个用户列表和一篇博客文章),我们可以这样做:

const express = require('express');
const app = express();
const fetchData1 = require('./fetchData1'); // 假设这是获取第一个数据块的函数
const fetchData2 = require('./fetchData2'); // 获取第二个数据块的函数

app.get('/page', async (req, res) => {
    try {
        const [data1, data2] = await Promise.all([fetchData1(), fetchData2()]);
        res.render('pageTemplate', { data1, data2 });
    } catch (error) {
        console.error(error);
        res.status(500).send('Server error');
    }
});

app.listen(3000, () => {
    console.log('Server running on port 3000');
});

在这个例子中,fetchData1()fetchData2() 是两个异步函数,它们分别负责从不同的数据源获取数据。Promise.all 确保这两个函数并发执行,且只有当两个都成功返回结果后,才会调用res.render 渲染页面。

这种方式不仅使代码更加清晰,而且提高了服务器性能,因为它允许同时加载多个数据块。

回到顶部