admin管理员组

文章数量:1401407

To share data between modules, a usual pattern is to capsulate the data into a mon module and import it in other modules.

In my case the data to be shared is a logger, which need to be initialized before used. I call init() at the entry point of my application.

// main.js

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

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

In other modules, the initialized logger can be used:

// moduleX.js

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

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

Above code works well in node.js. But if I change to ES6 module syntax, it doesn't work because ES6 module import is hoisted.

// 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');
}

With ES6 module, how can I initialize some data and share them to other modules?

There was a similar question but the answer doesn't fit my case.

Update:

Some answers suggest to put the code which access shared data into function so that the code isn't invoked immediately at module load. But what if I really need to access it during module loading? I updated my code to demonstrate the use case -- it would be too trivial to call logger(name) in every function if not make log as module scope const.

To share data between modules, a usual pattern is to capsulate the data into a mon module and import it in other modules.

In my case the data to be shared is a logger, which need to be initialized before used. I call init() at the entry point of my application.

// main.js

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

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

In other modules, the initialized logger can be used:

// moduleX.js

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

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

Above code works well in node.js. But if I change to ES6 module syntax, it doesn't work because ES6 module import is hoisted.

// 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');
}

With ES6 module, how can I initialize some data and share them to other modules?

There was a similar question but the answer doesn't fit my case.

Update:

Some answers suggest to put the code which access shared data into function so that the code isn't invoked immediately at module load. But what if I really need to access it during module loading? I updated my code to demonstrate the use case -- it would be too trivial to call logger(name) in every function if not make log as module scope const.

Share Improve this question edited May 23, 2017 at 12:16 CommunityBot 11 silver badge asked Dec 11, 2015 at 14:50 aleungaleung 10.4k4 gold badges61 silver badges71 bronze badges 5
  • 1 Why don't you just create another file initializeLogger.js where you call logger.init and import that one in main.js? – Paolo Moretti Commented Dec 11, 2015 at 15:31
  • @PaoloMoretti I have thought of this way, but it needs anther file, looks not concise enough to me. However, it seems to be the only way to solve it. Could you write it an answer so that I accept it? – aleung Commented Dec 11, 2015 at 16:28
  • What initialisation does the logger need before you call logger(…)? Wouldn't only log.debug(…) need to wait? – Bergi Commented Dec 12, 2015 at 21:12
  • @Bergi Output destination, application name, etc. You may said it's not necessary to do that for a logger. I'm asking for a general pattern to handle this kind of requirement: initialize an object and share it to every modules. – aleung Commented Dec 13, 2015 at 4:09
  • @aleung: Hm, the "similar question" you linked seems to answer this already. But I've written an explicit answer below. – Bergi Commented Dec 13, 2015 at 11:21
Add a ment  | 

5 Answers 5

Reset to default 3

Finally I solve it in the way that @PaoloMoretti mentioned in his ment.

Write a module in my app to init the logger for my app:

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

Import the initialization module once at the entry point of application, prior to imports of any other modules that use logger as well. It guarantees that the initialization is done before loading other modules.

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

Other modules can use initialized logger directly:

// @my/other_module

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

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

The dependency tree is:

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

Why I don't adopt the way that add a wrapper module which init and return a logger (as Bergi's answer) is because the modules uses logger could be reusable modules not in my application.

A logger, which need to be initialized before used. What if I need to access it during module loading?

Make an extra module with an initialised logger:

// 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');
}

Try to provide some entry points to your xxx.js and yyy.js modules or even make them as functions.

// 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');
}

You could have each module that has a dependency on some initialisation routine return a function that can be executed manually to invoke its functionality, rather than expose that functionality as an immediate side-effect of importing it. For example, in xxx.js:

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

Then place all initialisation operations within an entry file and invoke the modules defined in the above way after these operations are plete:

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

But what if I really need to access it during module loading?

Please see the amended code examples above. Pass the instance of logger to the function exported by each module.

After experiments, found that the BroadcastChannel api is perfect to share data or events easily between different es6 modules, tabs, workers, frames...

We can pass objects or arrays by using json stringify there too:

To send datas:

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

Example receiving, from another module:

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

It avoid to use any DOM elements to dispatchEvent, it simplify stuffs a lot!

本文标签: javascriptES6 share data between modulesStack Overflow