ECMAScript提案 "JSON模块"

70 阅读2分钟

在这篇博文中,我们研究了ECMAScript提案 "JSON模块"(由Sven Sauleau, Daniel Ehrenberg, Myles Borins和Dan Clark提出)。它让我们把JSON数据像ECMAScript模块一样导入。

为什么我们要像一个模块一样导入JSON?

长期以来,各种捆绑程序(如webpack)允许我们将JSON数据像ECMAScript模块一样导入。JSON模块把这变成了一个标准功能。

为什么这很有趣呢?它提供了一种方便的方式来使用,例如,在我们的应用程序中使用配置数据。以下面这个文件结构为例:

my-app/
  src/
    config-data.json
    main.mjs

my-app/src/config-data.json 看起来如下:

{
  "appName": "My App"
}

这是my-app/src/main.mjs

import configData from './config-data.json' assert {type: 'json'};
console.log(`I am ${configData.appName}!`);

assert ,直到最后的语法被称为一个 import assertion.JSON模块是创建导入断言的用例之一。

一个JSON模块的默认出口包含JSON数据。没有命名的出口。

通过fetch() 获取JSON数据

如果没有JSON模块,我们将不得不使用fetch()

async function fetchConfigData(relativePath) {
  const urlOfConfigData = new URL(
    relativePath, import.meta.url); // (A)
  const response = await fetch(urlOfConfigData.toString()); // (B)
  const json = await response.json(); // (C)
  return json;
}

const configData = await fetchConfigData('config-data.json');
console.log(`I am ${configData.appName}!`);

我们正在使用两个相对较新的功能:

fetch() 与JSON模块相比,Fetch API有两个缺点。

  • 代码稍微复杂一些。
  • Node.js目前没有内置支持fetch() 。(而且我怀疑JSON模块会比fetch() 更早得到支持。)

通过import() ,动态地导入JSON模块

之前的import 语句是静态的(在运行时固定)。我们也可以动态地导入JSON模块(在运行时可改变):

async function importConfigData(moduleSpec) {
  // The `await` can be ommitted, but is easier to understand
  return await import(moduleSpec, {assert: {type: 'json'}}); // (A)
}

const configData = await importConfigData('./config-data.json').default;
console.log(`I am ${configData.appName}!`);

请注意, import() 操作符(A行)返回一个模块命名空间对象。这就是为什么我们把属性.default (包含默认导出)分配给configData

你可能想知道为什么我们要在重要语句的末尾使用额外的语法:

import configData from './config-data.json' assert {type: 'json'};

为什么JavaScript不能通过查看文件名的扩展名来检测这是JSON?

import configData from './config-data.json';

这是不可能的,因为这可能会引起安全问题。浏览器从来不看文件名扩展名,他们看的是内容类型。而服务器是负责为文件提供内容类型的。因此,在导入一个.json 文件时,可能会发生两件事:

  • 我们自己的服务器可能会发送一个不同于application/json 的内容类型,而导入工作会在某些方面出错。
  • 对于外部服务器,事情就更危险了:如果它发送的文件的内容类型是text/javascript ,它就可能在我们的应用程序中执行代码。

因此,JavaScript在导入JSON时不会依赖内容类型。