Полезные практики javascript
Компонентный подход
Компонентный подход — код разбивается на повторно используемые модули с одинаковым интерфейсом. Для этого нужно описать их каких модулей состоит код, что они умеют делать и как они взаимодействуют друг с другом.
Какие сущности у нас есть?
- список отелей
- отель (как один из элементов списка)
- фотогалерея
Что умеют отели (каждый в отдельности)?
- создаваться из шаблона
- добавляться на страницу
- обрабатывать клики
- удалять обработчики
- удаляться со страницы
Что умеет галерея?
- показываться (в разметке уже есть галерея)
- принимать набор фотографий
- показывать нужную фотографию
- прятаться
Как связаны между собой галерея и отель?
Через список отелей. Он создает и то и другое и может контролировать изменения в каждом из них.
Объекты связываются друг с другом через общего предка, который слушает их события и вызывает их методы
Как связать два компонента (класса) между собой
Передаем свойству form
setOnSubmitHandler
callback, который переопределяет настройки экземпляра presenterInfo
и затем отрисовывает presenterInfo.render()
.
Обратите внимание, что значения элементов формы мы передаем только непосредственно внутри класса Form
: this._onSubmitHandler(data)
.
let form = new Form({
el: document.querySelector('.form')
});
let presenterInfo = new Presenter({
el: document.querySelector('.presenter')
});
form.setOnSubmitHandler(formData => {
presenterInfo.setData({
login: formData.login,
password: formData.password
});
presenterInfo.render();
});
// in form.js:
setOnSubmitHandler (handler) {
this.onSubmitHandler = handler;
}
// при submit формы выполняем установленные ранее callback
onSubmit (e) {
e.preventDefault();
let data = this.getData();
this.onSubmitHandler(data);
}
&& вместо if
//...
next: (x) => conditionFn(x) && obs.next(x)
//...
2-й операнд (obs.next(x)
) выполнится только тогда, когда первый операнд (conditionFn(x)
) true
.
Если первое значение false
, то второе не имеет смысла проверять.
Оптимизация (throttle - ускорение)
Оптимизация любых функций, который повторяются слишком часто.
Проверку запустим не чаще, чем в 100мс:
То есть на каждой следующей прокрутке Timeout очищается и только при останове и по прошествии 100мс, то только тогда будет вызван scroll.
var scrollTimeout;
// на каждый запуск скролла в эту переменную записываем новый Timeout,
// который отработает через 100мс
window.addEventListener("scroll", function(event){
clearTimeout(scrollTimeout);
scrollTimeout = setTimeout(function() {
//....
}, 100);
})
Фасад
Работаем например над общими компонентами по смыслу в одной папке.
Далее импортируем их в одном файле и экспортируем так:
//task.ts
import TasksComponent from './tasks.component';
import TaskEditorComponent from './task-editor.component';
import TaskMyDirective from './task-tooltip.directive';
export {
TASKS_DIRECTIVES,
TasksComponent,
TaskEditComponent,
TaskMyDirective
};
Далее мы можем экспортировать по отдельности или все вместе в другие модули:
//app.ts
import { TasksComponent, TaskEditComponent } from './tasks/tasks';
Конструкция !!
Конструкция !!
позволяет преобразовать любой выражение JS в его логический эквивалент.
!!"ЭЭЭЭЭ" === true //true
!!0 === false //true
Альтернатива свойству функции arguments
function log(target, name, descriptor) {
const original = descriptor.value;
if (typeof original === 'function') {
descriptor.value = function(...args) {
console.log(`Arguments: ${args}`);
try {
const result = original.apply(this, args);
console.log(`Result: ${result}`);
return result;
} catch (e) {
console.log(`Error: ${e}`);
throw e;
}
}
}
return descriptor;
}
Обратите внимание на то, что здесь мы использовали оператор расширения для того,
чтобы автоматически создать массив со всеми переданными методу аргументами. Это — современная альтернатива свойству функции arguments
.
Oператор расширения в действии:
var log = function(a, b, ...rest) {
console.log(a, b, rest);
};
log(1, 2, 3, 4, 5, 6); // 1 2 [ 3, 4, 5, 6 ]
Асинхронность
console.time('loop');
setTimeout(function() {
console.log('test');
}, 2000);
for (var i = 0; i < 3000000000; i++) {
var a = i/i;
}
console.timeEnd('loop');
Отсчет начинается с момента установки таймера, но обработка начнется только в конце основного потока, то есть при обработке цикле прошло, например, 2 секунды и значит надпись 'test'
будет выведена сразу же, без всяких ожиданий. jsfiddle.net
Занижаем скорость интернета в chrome
Вкладка no throttling
(throttle
- душить, дросселировать, мять; дроссель) и выбираем нужный девайс с соответствующей скоростью.
Как правильно организовывать асинхронный код?
Promise
Fetch API https://developer.mozilla.org/ru/docsFetch_API - это обертка над XMLHttpRequest, которая полностью работает на Promise.
try catch
Парсим ответ сервера в try catch
: если данные от сервера не JSON, то отдаем cb('Извините в данных ошибка');
let xhr = new XMLHttpRequest();
xhr.open('POST', url, true);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.onload = function (e) {
let result;
try {
result = JSON.parse(xhr.responseText);
} catch (e) {
cb('Извините в данных ошибка');
}
cb(result.status);
};
xhr.send(JSON.stringify(data));
Callback-функцию, асинхронная операция
/* upload.js */
// cb - собственно и есть наш callback
export default function (url, data, cb) {
let xhr = new XMLHttpRequest();
xhr.open('POST', url, true);
xhr.onload = function (e) {
let result = JSON.parse(xhr.responseText);
cb(result.status);
};
xhr.send(data);
}
/* index.js */
import fileUpload from './upload';
const formUpload = document.querySelector('#upload');
formUpload.addEventListener('submit', prepareSendFile);
function prepareSendFile(e) {
e.preventDefault();
let resultContainer = formUpload.querySelector('.status');
let formData = new FormData();
// передаем callback, который по scope видит и resultContainer и formUpload
fileUpload('/admin/upload', formData, function (data) {
resultContainer.innerHTML = data;
formUpload.reset();
});
}
Суть проста - наш callback будет выполнен лишь при определенных условиях. При этом callback-функция работает с нашим текущим кодом (resultContainer, formUpload) и мы заранее не знаем будет ли она выполнена и в точности какие данные придут в нее.
Комментарии к статье