javascript: module calls a function in the file that requires the module

时间:2019-05-19 04:12:57

标签: javascript node-modules

My first time writing a js library. The library is intended to execute, at specific times, functions in the file that required the library. Kind of like Angular executes user implemented hooks such as $onInit, except that, in my case, user can define an arbitrary number of functions to be called by my library. How can I implement that?

One way I have in mind is to define a registerFunction(name, function) method, which maps function names to implementations. But can user just give me an array of names and I automatically register the corresponding functions for them?

1 个答案:

答案 0 :(得分:1)

除非您有特定的要求,否则您的模块不需要知道所提供功能的名称。当您的模块调用这些函数时,它将通过对它们的直接引用而不是使用其名称来进行操作。

例如:

// my-module.js
module.exports = function callMyFunctions( functionList ) {
    functionList.forEach( fn => fn() )
}
// main application

const myFunc1 = () => console.log('Function 1 executing')
const myFunc2 = () => console.log('Function 2 executing')

const moduleThatInvokesMyFunctions = require('./my-module.js')

// instruct the module to invoke my 2 cool functions
moduleThatInvokesMyFunctions([ myFunc1, myFunc2 ])
//> Function 1 executing
//> Function 2 executing

看到调用者提供了对该模块的直接函数引用,然后该模块使用该模块,而无需关心甚至不知道这些函数被调用了什么。 (是的,您可以通过检查函数引用来获取它们的名称,但是为什么要麻烦呢?)

如果您想要更深入的答案或解释,这将有助于您进一步了解您的情况。您的库针对的环境是:浏览器? nodejs?电子?反应本机?


  

该库旨在在特定时间执行需要该库的文件中的功能

“在特定时间”向我提示一些基于事件的松散内容。因此,根据您要定位的平台,实际上可以使用真正的EventEmitter。在这种情况下,您会在每次调用函数时发明一个唯一的名称,然后模块将导出一个单例发射器。然后,调用者将为他们关心的每个事件分配事件处理程序。对于呼叫者,可能看起来像这样:

const lifecycleManager = require('./your-module.js')

lifecycleManager.on( 'boot', myBootHandler )
lifecycleManager.on( 'config-available', myConfigHandler )
// etc.

更粗略的处理方式是调用方提供功能字典:

const orchestrateJobs = require('./your-module.js')

orchestrateJobs({
    'boot': myBootHandler,
    'config-available': myConfigHandler
})

如果您不习惯使用EventEmitters,这可能会很吸引人。但是,按照这种方法,您需要考虑如何支持其他方案,例如希望删除功能的呼叫者和延迟注册。


快速草图显示如何在每个功能中使用apply

// my-module.js
module.exports = function callMyFunctions( functionList ) {
    functionList.forEach( fn => fn.apply( thisValue, arrayOfArguments ) )
}

请注意,此模块仍然不知道调用方为这些功能分配的名称。在此范围内,每个例程都带有绰号“ fn”。

我感觉到您对执行的工作方式有一些误解,这使您相信程序的各个部分需要知道程序其他部分的名称。但这不是延续传递样式的工作原理。


由于您要基于特定时间触发调用者函数,因此事件模型可能非常适合。这是一个大概的草图:

// caller

const AlarmClock = require('./your-module.js')

function doRoosterCall( exactTime ) {
    console.log('I am a rooster! Cock-a-doodle-doo!')
}

function soundCarHorn( exactTime ) {
    console.log('Honk! Honk!')
}

AlarmClock.on('sunrise', doRoosterCall)
AlarmClock.on('leave-for-work', soundCarHorn)
// etc

要做到这一点,您可以做类似...

// your-module.js

const EventEmitter = require('events')

const singletonClock = new EventEmitter()

function checkForEvents() {
    const currentTime = new Date()

    // check for sunrise, which we'll define as 6:00am +/- 10 seconds
    if(nowIs('6:00am', 10 * 1000)) {
        singletonClock.emit('sunrise', currentTime)
    }

    // check for "leave-for-work": 8:30am +/- 1 minute
    if(nowIs('8:30am', 60 * 1000)) {
        singletonClock.emit('leave-for-work', currentTime)
    }
}

setInterval( checkForEvents, 1000 )

module.exports = singletonClock

({nowIs有点费时。在进行类似cron的工作时,您应该假设在时间值完全匹配时几乎不会触发心跳功能,因此您需要可以提供“足够接近”的比较。我之所以没有提供任何暗示,是因为(1)这里似乎是一个外围问题,并且(2)我确信Momentjs,date-fns或其他软件包提供了很好的功能,因此您不需要自己实施。