请教个Nodejs nodeclub源码问题,发送邮件会不会导致UI界面阻塞?

请教个Nodejs nodeclub源码问题,发送邮件会不会导致UI界面阻塞?

我在源码中看到一个services目录,里面有at.js/mail.js/message.js。 我原以为这几个是基于队列作为服务后台执行。

因为我nodejs初学,对其异步模型还不算特别了解,不知道发送邮件如果耗时很长会不会导致UI阻塞,于是我简单修改了一下源码,在mail.js的sendmail方法里面增加了延时处理,结果发现注册帐号时,界面会一直等待,难道不能界面先返回,邮件慢慢发送?

4 回复

当然可以。让我们详细探讨一下这个问题,并通过一些示例代码来解释为什么发送邮件可能会导致UI界面阻塞,以及如何解决这个问题。

问题分析

在Node.js中,通常我们会使用异步编程模型来避免阻塞UI线程。然而,如果你在处理邮件发送时使用了同步的方式(例如,直接调用一个耗时很长的函数),那么这确实会导致UI界面在邮件发送完成之前一直处于等待状态。

示例代码

假设我们有一个简单的邮件发送功能,使用nodemailer库来发送邮件。以下是一个可能的实现:

const nodemailer = require('nodemailer');

// 创建一个SMTP传输对象
let transporter = nodemailer.createTransport({
    host: 'smtp.example.com',
    port: 587,
    secure: false, // true for 465, false for other ports
    auth: {
        user: 'your-email@example.com', // 发件人邮箱
        pass: 'your-password' // 邮箱密码或授权码
    }
});

async function sendEmail(to, subject, text) {
    const mailOptions = {
        from: '"Your Name" <your-email@example.com>', // 发件人
        to: to, // 收件人
        subject: subject,
        text: text
    };

    // 发送邮件
    await transporter.sendMail(mailOptions);
}

module.exports = { sendEmail };

问题所在

如果你直接在路由处理函数中调用sendEmail并等待其完成,那么UI界面将会被阻塞直到邮件发送完毕:

app.post('/register', async (req, res) => {
    // 处理注册逻辑...
    
    // 发送欢迎邮件
    await sendEmail(req.body.email, 'Welcome!', 'Hello and welcome to our service!');
    
    // 返回响应
    res.send('Registration successful. Please check your email.');
});

解决方案

为了避免UI阻塞,你可以将邮件发送操作放到一个后台任务队列中,这样前端请求可以立即返回响应,而邮件则会在后台异步发送。一种常见的做法是使用bullkue等队列库。

使用Bull队列

  1. 安装Bull库:
npm install bull
  1. 创建一个队列处理器:
const Queue = require('bull');

const emailQueue = new Queue('email', 'redis://localhost:6379');

emailQueue.process(async (job) => {
    const { to, subject, text } = job.data;
    await sendEmail(to, subject, text);
});
  1. 修改邮件发送逻辑,将邮件添加到队列中:
module.exports = { 
    sendEmail: async (to, subject, text) => {
        await emailQueue.add({ to, subject, text });
    }
};
  1. 在路由处理函数中调用新的sendEmail方法:
app.post('/register', async (req, res) => {
    // 处理注册逻辑...
    
    // 将邮件发送任务添加到队列
    await sendEmail(req.body.email, 'Welcome!', 'Hello and welcome to our service!');
    
    // 立即返回响应
    res.send('Registration successful. Please check your email.');
});

通过这种方式,前端请求不会被阻塞,用户可以立即收到响应,而邮件则会在后台异步发送。


ui 不会阻塞,你发送完毕后,不用等,发送成功的回调处理就好,直接进入下一步页面处理,监听发送邮件事件,等事件完成后,回调进行处理

但是实际测试,我在mail.js的sendmail方法里面增加了延时处理(循环之类),结果发现注册帐号时,界面会一直等待,等邮件全部发送完才能继续。

发送邮件操作是否会导致UI界面阻塞主要取决于你的代码如何实现。在Node.js中,异步编程模型是解决这类问题的关键。

解释

  1. 异步发送邮件:为了防止UI界面阻塞,你可以使用异步方式来发送邮件。通常可以借助nodemailer库实现异步发送邮件。

  2. 示例代码

    • 首先安装nodemailer库(如果还没有安装):
      npm install nodemailer
      
    • mail.js文件中实现异步发送邮件的方法:
const nodemailer = require('nodemailer');

// 创建一个发送邮件的函数
async function sendMail(to, subject, text) {
    let transporter = nodemailer.createTransport({
        service: 'gmail',
        auth: {
            user: 'your-email@gmail.com',
            pass: 'your-password'
        }
    });

    // 邮件配置
    let mailOptions = {
        from: 'your-email@gmail.com', // 发件人
        to: to, // 收件人列表
        subject: subject, // 主题
        text: text // 文本内容
    };

    try {
        await transporter.sendMail(mailOptions);
        console.log("邮件发送成功");
    } catch (error) {
        console.error("邮件发送失败:", error);
    }
}

module.exports = { sendMail };
  1. 调用发送邮件的函数
    • 当你需要发送邮件时,只需要调用sendMail函数即可,这不会阻塞UI线程。
const { sendMail } = require('./mail');

async function registerUser(email) {
    // 注册逻辑...
    await sendMail(email, '欢迎注册', '感谢您的注册!');
    // 其他逻辑...
}

总结

通过上述示例代码,可以看到发送邮件操作是异步的,不会阻塞UI线程。因此,用户界面可以立即返回响应,而邮件会在后台异步发送。

回到顶部