【问题标题】:Does synchronous programming on an Express server block other visitors from loading the page?Express 服务器上的同步编程是否会阻止其他访问者加载页面?
【发布时间】:2018-06-29 23:40:26
【问题描述】:

我正在编写一个简单的(单页)网络应用程序,它依赖于从文件加载天气数据(我有一个单独的脚本来定期刷新数据,因此我不必为每个文件执行大量 HTTP 请求访客)。

我正在使用fs.readFileSync(),因为在将数据作为 Javascript 对象加载之前,所有代码都不起作用。所以我想在这个特定的实例中我需要同步编程。

我是 node.js 和异步编程的新手,我有一个问题:假设,假设 fs.readFileSync 需要 3 秒来加载文件,而其他所有内容都会立即执行。如果访问者 A 访问该站点,则页面加载需要 3 秒。在 t=1 秒,如果我收到一个新的访客 B,访客 B 需要等待 3 秒还是 5 秒?

同步代码会阻止后续代码仅为当前访问者执行,还是会阻止 Express 为任何其他访问者提供服务?

更新:在收到回复告诉我在 Express 网络服务器上同步操作有什么不好的想法后,我已将代码更改为:

var locationList = JSON.parse(fs.readFileSync('locationList.json'));

router.get('/', function(req, res, next) {
    res.render('index', {
        locationList: locationList
    });
});

收件人:

var locationList;
fs.readFile('locationList.json', (err, data) => {
    if (err) throw err;
    locationList = JSON.parse(data);
});

router.get('/', function(req, res, next) {
    res.render('index', {
        locationList: locationList
    });
});

只是想知道这是否是正确的方法。

【问题讨论】:

  • 其实你的第一个sn-p还不错。请注意,它确实会在 打开服务器并为任何客户端提供服务之前的 3 秒内读取文件 - 这对于每个客户端都会立即发生。请注意,它不会为收到的每个请求再次读取文件。当然,这也意味着当文件定期更新时响应不会改变,至少在你重新启动服务器之前不会改变。
  • 我什至认为第二个脚本要糟糕得多。它不是在前 3 秒内不为任何请求提供服务,而是为它们提供服务,但使用了错误的数据。

标签: javascript node.js express asynchronous


【解决方案1】:

你不应该对 io 使用同步函数,唯一应该同步的函数是 require 哪个节点用来拉入依赖文件,其他一切都应该是异步的,并且使用 async 函数你仍然可以保持在您的程序中使用相同的控制流,使其“看起来”同步。

您可以使用util.promisify 将函数转换为promise,然后使用async 函数等待promise 解析。

import { readFile } from 'fs'
import { promisify } from 'util'

const readFilePromise = promisify(readFile)

async function app() {
  try {
    const file = await readFilePromise('filename.txt')
    console.log('file:', file)
  } catch (e) {
    console.error('error:', e)
  }
}

app()

【讨论】:

    【解决方案2】:

    是的,它会“阻止”服务器。所以你应该避免频繁使用同步函数。您还可以使用负载均衡器或集群来提高跨多个实例分配负载的性能。

    Express Performance Guide

    【讨论】:

    • 你不应该完全避免使用同步函数,这是夸大其词 - 只要确保潜在的 长期运行 操作是异步的 - 在 OP 的情况下,它是一个 IO 操作天生就很慢,因此非常适合异步执行。
    • @Nicholas 是的,我并不是说他永远不能使用同步功能,只是不推荐这样做。有时需要使用同步功能
    • 我大体上同意,但我会更改措辞。不建议在 I/O 或网络操作上使用 - 其他所有操作都是同步进行的。
    • 那么这会是正确的实现吗? var locationList; fs.readFile('locationList.json', (err, data) => { if (err) throw err; locationList = JSON.parse(data); }); router.get('/', function(req, res, next) { res.render('index', { locationList: locationList }); });
    • 在这种情况下可以使用它。如果使用同步,它只会在服务器启动时阻塞线程。如果你使用异步,服务器会启动得更快,但你无法知道函数是否完成。
    猜你喜欢
    • 1970-01-01
    • 2021-12-05
    • 1970-01-01
    • 2013-07-09
    • 2016-06-08
    • 2012-06-09
    • 2016-12-07
    • 2012-11-07
    • 2020-05-22
    相关资源
    最近更新 更多