Хабр Курсы для всех
РЕКЛАМА
Практикум, Хекслет, SkyPro, авторские курсы — собрали всех и попросили скидки. Осталось выбрать!
define(function(require, module, exports){
// . . . здесь код модуля . . .
});
user.settings.currency="rub" означает что все цены нужно умножить на 30, ну и т.д.)var request = require('request');
request.get(config).then(run, epicFail);
// и с обработкой ошибки и перезапросом
var Attempt = require('attempt');
new Attempt(function promiseGenerator() {
return request.get(config);
}, function timeoutGenerator(error, attemptNo) {
// Если 404 или попыток больше 3 - не повторяем запрос
if (error.status === 404 || attemptNo > 3) {
return Infinity;
}
var repeatRequestIn = attemptNo * 2000;
return repeatRequestIn;
})
.then(run, epicFail, notifyUser);
settings.currency предоставляет функцию getPrice (которая внутри себя содержит всю логику просчета цены исходя из настроек). Ну и помимо этого, дополняет данные функциями уведомления об изменении этих данных, а так же непосредственно предоставляет интерфейс изменения этих данных. То есть наш модуль это модель в MV* (например модуль возвращает объект на основе Backbone.Model, с данными загруженными из API). Соответственно отсутствие данных = отсутствие объекта-модели = невозможность работы приложения, которая обрабатывается в штатном режиме (то есть для всей системы наш модуль — это и есть данные, и только сам модуль определяет откуда реальные данные берутся, из файла, из АПИ, может быть несколько запросов к АПИ и т.п.)// config.js
var request = require('request'),
_ = require('underscore');
var promise = request.get('/cfg.json').then(function (data) {
_.extends(exports, data);
});
exports.then = promise.then.bind(promise);
// index.js
require('config').then(function () {
require('main');
}, require('epicFailHandler'));
// main.js
var config = require('config');
exports.getPrice = function () {
console.log(config.currency);
};
// .lmd.js
{
...,
"modules": {
"config": "@http://site.com/user/config",
...
},
"async": true,
"shortcuts": true,
"promise": true
}
// index.js
// грузим асинхронный модуль, который резолвится по ссылке на http://site.com/user/config
// и после загрузки будет доступен синхронно под именем "config" и "http://site.com/user/config"
require.async('config').then(function (config) {
require('main');
}, require('epicFailHandler'));
// main.js
var config = require('config');
exports.getPrice = function () {
console.log(config.currency);
};
provide(), то тогда ошибки данных становятся ошибками модуля и мы теряем над ними контроль.modules.define('ymaps', ['loader'], function(provide) {
loader.load('тут_урл_для_ymaps_api', function() {
ymaps.ready(function() {
provide(ymaps);
});
})
});
modules.define('my-module', ['ymaps', 'inherit'], function(provide, ymaps, inherit) {
var MyClass = inherit(ymaps.GeoObject, { .... });
provide(MyClass);
});
// Активный по своей конфигурации
require.bundle('userSettings'); // сам себя запустит и будет использовать как модули из основой части так и свои
// Пассивный по своей конфигурации
require.bundle('bunchOfViews').then(function () {
require('viewFromBunchOfViews').doStuff();
});
// ready.js
var lang = require('lang'),
config = require('config'),
ymapsApi = config.ymapsApi.replace('%lang', lang);
var maps = $.getScript(ymapsApi).pipe(function () {
var dfd = $.Deferred();
window.ymaps.ready(dfd.resolve);
return dfd.promise();
});
var ready = $.Deferred();
$(ready.resolve);
module.exports = $.when(maps, ready.promise());
// index.js
require('ready').pipe(function () {
require('mapView')('#map');
});
// views/map.js
var ymaps = require('ymaps'); // из глобалов
// ...
То есть, опять вводя знания в свой код, что он неработоспособен, пока кто-то где-то как-то снаружи не обеспечит это.Пример с внешним api это исключение, которое чинится 1 «асинхронным» модулем. Притом, что эту зависимость мы можем представить как синхронно (тег скрипт) так и асинхронно и вызов
require('ymaps') в обоих случаях отработает одинакого. Зависимость модуля обеспечивается либо кодом, либо конфигом, либо явной зависимостью(тег скрипт).Почему же для модульной системы эти различия должны играть такую роль?В «асинхронности» для модулей нет смысла потому как 95% модулей могут быть получены без видимой блокировки основного потока (они загружаются при старте приложения). А для тех 5% модулей, которые мы должны догружать мы можем сделать обвязку, которая примит на себя всю асинхронноть(за счет теж же промисов) и обеспечит точечый контроль ошибок дозагрузки модуля. Я устал писать обертки над модулями(AMD-стиль), которые никогда не будут использоваться по назначению, поэтому я ввожу это различие. И хочу использовать весь потенциал динамических require без регулярок и прочей магии.
Притом, что эту зависимость мы можем представить как синхронно (тег скрипт) так и асинхронно и вызов require('ymaps') в обоих случаях отработает одинакого.
В «асинхронности» для модулей нет смысла потому как 95% модулей могут быть получены без видимой блокировки основного потока (они загружаются при старте приложения)
Через тэг ты получишь только заглушку, у которой нужно дождаться еще ready.Действуем по аналогии с DOMContentLoaded — см мой пример в ready.js
О какой блокировке основного потока идет речь при «асинхронности» модулей?Это если бы я синхронно грузил модули с сервера
Действуем по аналогии с DOMContentLoaded — см мой пример в ready.jsВсе-таки, это больше похоже на «Делаем костыли по аналогии с DOMContentLoaded» ;)
Так гораздо естественней
http монжо так или иначе абстрагировать реально естественными способами вроде заводов или наследования. (Естественными=Привычными способами) Манкипатчинг exports модуля это какаое-то не привычное для разработчика поведение. Эту особенность тянут за собой уровни переопределения BEM?часто это бывает просто избыточнои подобные мысли чаще ведут к не поддерживаемому коду и мыслям: «А давай ка я просто проманкипатчу, зачем писать абстракцию?!»
Пример чего именно ты хочешь чтобы я привел?Пример реализации интерфейса http под ноду и браузер, учитывая поддерживаемость и переносимость кода.
modules.define('http', ['inherit'], function(provide, inherit) {
provide(inherit({
...
request : function(params) {
if(this.hasCache(params)) {
return this.getCache(params);
}
var result = this.doRequest(params);
this.setCache(params, result);
return result;
},
doRequest : function(params) {}
...
});
});
modules.define('http', ['inherit'], function(provide, inherit, base) {
provide(inherit(base, {
...
doRequest : function(params) {
var xhr = this._createXhr();
return xhr.send(...);
}
...
});
});
modules.define('http', ['inherit'], function(provide, inherit, base) {
var http = require('http');
provide(inherit(base, {
...
doRequest : function(params) {
return http.request(...);
}
...
});
});
http.vanilla. Вижу неявное перекрытие абстрактного модуля и внедрение ненужной абстракции над модульной системой Node.js и не вижу преимуществ над:// node_modules/request.js - node
var http = require('http'),
abstractHttp = require('../lib/abstract-http');
// extends - как вариант наследования
module.exports = abstractHttp.extends({
doRequest : function(params) {
return http.request(...);
}
});
// js/request.js - browser
var $ = require('$'),
abstractHttp = require('abstract-http');
module.exports = abstractHttp.extends({
doRequest : function(params) {
return $.ajax(...);
}
});
// index.js - common
var request = require('request');
request.get('http://ya.ru/').then(function () {
});
$ cat js/*.js build.js
$ cat js/*.js > build.js
Путь JavaScript модуля