ES6:模块之间共享数据

时间:2015-12-11 14:50:12

标签: javascript module ecmascript-6

要在模块之间共享数据,通常的模式是将数据封装到公共模块中并将其导入其他模块。

在我的情况下,要共享的数据是记录器,需要在使用之前进行初始化。我在申请的入口处致电init()

// main.js

let logger = require('@my/logger');
logger.init({...});

let xxx = require('./moduleX');
let yyy = require('./moduleY');

在其他模块中,可以使用初始化记录器:

// moduleX.js

let logger = require('@my/logger');
const log = logger('moduleX');

function x() {
  log.debug('some msg');
}

上面的代码在node.js中运行良好。但是,如果我更改为ES6模块语法,它将无效,因为ES6模块导入已挂起。

// main.js

import {logger} from '@my/logger';
logger.init({...});          // this line is run after import moduleX
import {x} from './moduleX';

// moduleX.js

import {logger} from '@my/logger';
const log = logger('moduleX');        // logger is not initialized !

export function x() {
  log.debug('some msg');
}

使用ES6模块,如何初始化某些数据并将其共享给其他模块?

有类似的question,但答案不适合我的情况。

更新:

有些答案建议将访问共享数据的代码放入函数中,以便在模块加载时不会立即调用代码。但是如果我真的需要在模块加载期间访问它呢?我更新了我的代码来演示用例 - 如果没有将logger(name)作为模块范围const,那么在每个函数中调用log都是太微不足道了。

5 个答案:

答案 0 :(得分:2)

最后,我以@PaoloMoretti在评论中提到的方式解决了这个问题。

在我的应用程序中编写一个模块,为我的应用程序启动记录器:

// logger_init.js
import {logger} from '@my/logger';
logger.init({...});

在导入任何其他使用记录器的模块之前,在应用程序的入口点导入初始化模块一次。它保证在加载其他模块之前完成初始化。

// main.js
import './logger_init'; 
import {x} from '@my/other_module';
import {y} from './module_in_myapp';

其他模块可以直接使用初始化记录器:

// @my/other_module

import {logger} from '@my/logger';
const log = logger('moduleX');       // logger has been initialized

export function x() {
  log.debug('some msg');
}

依赖树是:

                           <init>
myapp --+--> logger_init ------------> @my/logger
        |                       <use>   ↑ 
        +--> module_in_myapp -----------+
        |                       <use>   |
        +--> @my/other_module ----------+

为什么我不采用添加包装器模块的方式来启动并返回一个记录器(如Bergi的答案)是因为模块使用记录器可能是不在我的应用程序中的可重用模块。

答案 1 :(得分:0)

尝试为xxx.js和yyy.js模块提供一些入口点,甚至将它们作为函数。

// main.js
import {logger} from '@my/logger';
import * as xxx from './xxx';

logger.init({...});

xxx.run();

// xxx.js
import {logger} from '@my/logger';
export function run () {
   logger.debug('In xxx');
}

答案 2 :(得分:0)

您可以让每个依赖于某些初始化例程的模块返回一个可以手动执行以调用其功能的函数,而不是将该函数公开为导入它的直接副作用。例如,在xxx.js

// xxx.js
export default function (log) {
    log('xxx');
}

然后将所有初始化操作放在一个条目文件中,并在完成这些操作后调用上面中定义的模块:

// main.js
import xxx from './xxx';
import {logger} from '@my/logger';
logger.init({...});
xxx(logger);
  

但是如果我真的需要在模块加载期间访问它呢?

请参阅上面修改过的代码示例。将logger的实例传递给每个模块导出的函数。

答案 3 :(得分:0)

  

记录器,需要在使用前进行初始化。如果我需要在模块加载期间访问它,该怎么办?

使用初始化记录器创建一个额外的模块:

// main.js
import {x as xxx} from './moduleX';
import {y as yyy} from './moduleY';

// logger_ready.js
import {logger} from '@my/logger';
logger.init({…});
export default logger;

// moduleX.js
import logger from 'logger_ready';
const log = logger('moduleX');        // logger is initialized here!

export function x() {
  log.debug('some msg');
}

答案 4 :(得分:0)

经过实验,发现BroadcastChannel api非常适合在不同的es6模块,标签,工作程序,框架之间轻松共享数据或事件。

我们也可以通过使用json字符串化来传递对象或数组:

要发送数据:

new BroadcastChannel('myapp_section8').postMessage('Hello world!')

从另一个模块接收示例:

new BroadcastChannel('myapp_section8').addEventListener('message', function(e){
  console.log(e.data) 
})

它避免使用任何DOM元素来 dispatchEvent ,它大大简化了内容!