RequireJS를 사용하여 전역 객체 또는 싱글 톤을 어떻게 전달합니까?
메인 페이지 수준에서 코드를 작성하고 있고 2 개의 종속성이 동일한 객체 인스턴스를 필요로하며이를 종속성으로 명시한다고 가정 해 보겠습니다. 이에 대해 적절한 방법은 무엇입니까?
기본적으로 내가 원하는 것은 "이 종속성이로드되지 않은 경우 ...로드하십시오. 그렇지 않으면 이미로드 된 동일한 인스턴스를 사용하고 해당 인스턴스를 전달하십시오."라고 말하는 것입니다.
모듈 수준 변수로 만들 것입니다. 예를 들면
// In foo.js
define(function () {
var theFoo = {};
return {
getTheFoo: function () { return theFoo; }
};
});
// In bar.js
define(["./foo"], function (foo) {
var theFoo = foo.getTheFoo(); // save in convenience variable
return {
setBarOnFoo: function () { theFoo.bar = "hello"; }
};
}
// In baz.js
define(["./foo"], function (foo) {
// Or use directly.
return {
setBazOnFoo: function () { foo.getTheFoo().baz = "goodbye"; }
};
}
// In any other file
define(["./foo", "./bar", "./baz"], function (foo, bar, baz) {
bar.setBarOnFoo();
baz.setBazOnFoo();
assert(foo.getTheFoo().bar === "hello");
assert(foo.getTheFoo().baz === "goodbye");
};
싱글 톤에 대한 API를 제공하십시오.
그리고 느리게로드되었는지 확인하십시오. 가장 쉬운 방법은 크로스 브라우저 도우미를 제공하는 밑줄과 같은 추상화 라이브러리를 사용하는 것입니다. 다른 옵션은 ES5 Object.defineProperty 또는 사용자 정의 getter / setter입니다.
이 경우 _.once
생성자의 결과가 첫 번째 호출 후 캐시되도록 보장하며 기본적으로 지연로드합니다.
define(function() {
var constructor = _.once(function() {
...
});
return {
doStuffWithSingleton: function() {
constructor().doStuff();
}
};
});
_.once
밑줄에서.
캡슐화에 대한 Raynos의 우려와 메시징 서비스에 대한 몇 가지 메서드를 공개하고자하는 OP의 설명을 결합하면 이것이 올바른 방법이라고 생각합니다.
// In messagingServiceSingleton.js
define(function () {
var messagingService = new MessagingService();
return {
notify: messagingService.listen.bind(messagingService),
listen: messagingService.notify.bind(messagingService)
};
});
// In bar.js
define(["./messagingServiceSingleton"], function (messagingServiceSingleton) {
messagingServiceSingleton.listen(/* whatever */);
}
// In baz.js
define(["./messagingServiceSingleton"], function (messagingServiceSingleton) {
messagingServiceSingleton.notify(/* whatever */);
}
Function.prototype.bind
모든 브라우저에있는 것은 아니므로 Mozilla가 제공 하는 것과 같은 폴리 필을 포함해야 합니다 .
대체 (내 생각에는 아마도 더 나은) 접근 방식은 메시징 서비스 객체 자체를 모듈로 만드는 것입니다. 이것은 다음과 같이 보일 것입니다.
// In messagingService.js
define(function () {
var listenerMap = {};
function listen(/* params */) {
// Modify listenerMap as appropriate according to params.
}
function notify(/* params */) {
// Use listenerMap as appropriate according to params.
}
return {
notify: notify
listen: listen
};
});
모듈을 사용하는 모든 사람에게 동일한 notify
및 listen
메서드를 노출하고 항상 동일한 개인 listenerMap
변수를 참조하므로 원하는대로 수행해야합니다. 또한에 대한 필요성을 Function.prototype.bind
제거하고 메시징 서비스 자체와 단일 사용을 강제하는 모듈 간의 불필요한 구분을 제거합니다.
다음은 모듈 자체가 해당 모듈 내의 변수가 아닌 공유 변수 인 버전입니다.
define('foo', [], {bar: "this text will be overwritten"});
define('bar', ["foo"], function (foo) {
return {
setBarOnFoo: function () { foo.bar = "hello"; }
};
});
define('baz', ["foo"], function (foo) {
return {
setBazOnFoo: function () { foo.baz = "goodbye"; }
};
});
require(["foo", "bar", "baz"], function (foo, bar, baz) {
bar.setBarOnFoo();
baz.setBazOnFoo();
$('#results').append(foo.bar + ' ' + foo.baz);
});
// reads: hello goodbye
As a variation of Domenic's answer, you can use the 'exports' magic module to automatically generate a reference for the module -- "Properties added to the exports object will be on the public interface of the module, no need to return any value." This avoids having to call the getTheFoo()
function to obtain a reference.
// In foo.js
define(['exports'], function (foo) {
foo.thereCanBeOnlyOne = true;
});
// In bar.js
define(["exports", "./foo"], function (bar, foo) {
bar.setBarOnFoo = function () { foo.bar = "hello"; };
});
// in baz.js
define(["exports", "./foo"], function (baz, foo) {
baz.setBazOnFoo = function () { foo.baz = "goodbye"; };
});
// In any other file
define(["./foo", "./bar", "./baz"], function (foo, bar, baz) {
bar.setBarOnFoo();
baz.setBazOnFoo();
assert(foo.bar === "hello");
assert(foo.baz === "goodbye");
assert(foo.thereCanBeOnlyeOne);
});
To address the comment below, I personally have found the above convention to be useful. Your mileage may vary, but feel free to adopt the convention if you think it is useful. The convention boils down to these two rules:
- Declare 'exports' as the first dependency in the define array.
- Name the parameter in the function after the JavaScript file.
Using the name of file, e.g. for foo.js name the variable 'foo', increases the readability of the code as most developers will define 'foo' as the parameter for the foo.js dependency. When scanning the code or using grep, it is easy to find all references to 'foo' use both inside and outside the module and it makes it easy to pick out what the module is exposing to the public. For example, renaming bar.setBarOnFoo
to bar.setFooBar
is much easier if the declaration in the bar.js module mirrors the usage in other files. A simple search and replace of bar.setBarOnFoo to bar.setFooBar across all files will accomplish the task.
I was in this scenario:
For different reasons I needed to call a function that was on a requirejs module, but the click that fired that call was out of require.
The way I fixed this was creating a requirejs modure that writes over the window object.
define("one", [], function() {
window.popupManager = (function () {
console.log ('aca');
var popUpManager = function () {
self = this;
self.CallMe = function ()
{
alert ('someone calls');
};
};
return new popUpManager();
})();
});
require(['one']);
window.popupManager.CallMe();
This way if any piece of code that is out of the require spectrum (I know it shouldn't be this way) can call functions of this require that writes over the window object.
I really know this is not an "elegant" solution, but it may help you in case of an emergency.
ReferenceURL : https://stackoverflow.com/questions/5608685/using-requirejs-how-do-i-pass-in-global-objects-or-singletons-around
'programing' 카테고리의 다른 글
협업시 구성 파일을 관리하는 방법은 무엇입니까? (0) | 2021.01.15 |
---|---|
npm은 루트로 실행하지 않는 것을 어떻게 / 왜 권장합니까? (0) | 2021.01.15 |
JavaScript에서 "(function () {}) ()"및 "(function () {} ())"기능이 동일합니까? (0) | 2021.01.15 |
콘텐츠 길이 헤더없이 S3로 파일 업로드를 스트리밍 할 수 있습니까? (0) | 2021.01.15 |
엔티티 프레임 워크 6에 MySQL 연결을 사용할 수 없습니다. (0) | 2021.01.15 |