Жизнь после js-фреймворков

Ваганов Андрей

Aggregion

В итоге

 

  • Задачи решены
  • Достаточный уровень качества
  • Время/качество

Framerworks/Libs

 

  • jQuery (август 2006)
  • Knockout (июль 2010)
  • Backbone (октябрь 2010)
  • AngularJS (октябрь 2010)
  • Ember (июнь 2011)
  • Meteor (декабрь 2011)
  • React (май 2013)
  • ??? (???)

Что делать?

  1. Ничего
  2. Только PlainJS
  3. Framewoks+PlainJS

Что нужно

 

  • Работа с DOM и HTML

  • Ajax
  • Promise
  • TwoWay data binding

GetElement

var $obj = $("#list .sublist .li");
var n = document.querySelectorAll("#list .sublist li");

GetElement

GetElement

$("#main ul:first-child").hide();
document
    .querySelector("#main ul:first-child")
    .style.display = 'none';

GetElement

GetElement

(function(dq) {
  'use strict';

  dq('.yourClass').style.display = "none";
  
}(document.querySelector));

Show/Hide

jQuery

PlainJS

el.style.display = 'none';
el.style.display = '';
$(el).hide();
$(el).show();

Show/Hide perfomance

jQuery

PlainJS

$.each(array, function(index, element) { e = element; })
for (var i = 0, len = array.length; i < len; i++) { 
    e = array[i]; 
}

AJAX 

Post

$.ajax({
  type: 'POST',
  url: '/my/url',
  data: data
});
var request = new XMLHttpRequest();
request.open('POST', '/my/url', true);
request.setRequestHeader(
    'Content-Type',
    'application/x-www-form-urlencoded; charset=UTF-8'
);
request.send(data);

AJAX 

Get

$.get('//example.com', function (data) {

})
var httpRequest = new XMLHttpRequest()
httpRequest.onreadystatechange = function (data) {
  
}
httpRequest.open('GET', url)
httpRequest.send()

Promise

Angular promise

function asyncGreet(name) {
  return $q(function(resolve, reject) {
    setTimeout(function() {
      if (true) {
	resolve('Hello, ' + name + '!');
      } else {
        reject(
          'Greeting ' + name + '!' +
	  'Unfortunally "' + name + '" is not allowed.' +
          ' Choose another name');
      }
    }, 1000);
  });
}
	
var promise = asyncGreet('Robin Hood');
promise.then(function(greeting) {
	alert('Success: ' + greeting);
}, function(reason) {
	alert('Failed: ' + reason);
});

Promise

jQuery promise

function asyncGreet(name) {

    var d = $.Deferred();

    setTimeout(function () {
        if (true) {
            d.resolve('Hello, ' + name + '!');
        } else {
            d.reject(
                'Greeting ' + name + '!' +
                'Unfortunally "' + name + '" is not allowed.' +
                ' Choose another name');
        }
    }, 1000);

    return d.promise();
}

var promise = asyncGreet('Robin Hood');
promise.then(function (greeting) {
    alert('Success: ' + greeting);
}, function (reason) {
    alert('Failed: ' + reason);
});

Promise

AJAX native promise

function Http () {

    this.makeRequest = makeRequest;
    
    function makeRequest(method,url,data) {
        var data = data || '';

        return new Promise(function(resolve, reject) {
            var req = new XMLHttpRequest();
            req.open(method, url);

            req.onload = function() {
                if (req.status == 200) {
                    resolve(req.response);
                }
                else {
                    reject(Error(req.statusText));
                }
            };
            req.onerror = function() {
                reject(Error("Something went wrong ... "));
            };
            req.send(data);
        });
    }
    
}

Promise

AJAX native promise using

var http = new Http();
 
 http.makeRequest('GET', 'data.json').then(
    function (response) {
        console.log("Success!", response);
    }, function (error) {
        console.error("Failed!", error);
    });

2-way data binding

function observable(value) {
  var listeners = [];
  function notify(newValue) {
    listeners.forEach(function(listener){ listener(newValue); });
  }
  function accessor(newValue) {
    if (arguments.length && newValue !== value) {
      value = newValue;
      notify(newValue);
    }
    return value;
  }
  accessor.subscribe = function(listener) { listeners.push(listener); };
  return accessor;
}

var a = observable(3), b = observable(2);
var c = observable(a() + b());

a.subscribe(function(){ c(a() + b()); });
b.subscribe(function(){ c(a() + b()); });

console.log(c()); // 5
a(10);
console.log(c()); // 12
b(7);
console.log(c()); // 17

2-way data binding

2-way data binding

{ ... }

function computed(calculation, dependencies) {
  // вычислим сразу значение наблюдаемого
  var value = observable(calculation());

  // регистрируем слушателей для каждой зависимости
  function listener() { value(calculation()); }
    
  dependencies.forEach(function(dependency) {
    dependency.subscribe(listener);
  });

  // сделаем обертку над значением чтобы пользователи computed()
  // чтобы пользователи не могли вручную изменить значение
  function getter() { return value(); }
  getter.subscribe = value.subscribe;

  return getter;
}

var a = observable(3), b = observable(2);
var c = computed(function(){ return a() + b(); }, [a, b]);

console.log(c()); // 5
a(10);
console.log(c()); // 12
b(7);
console.log(c()); // 17

2-way data binding

{...}

{...}

function bindValue(input, observable) {
  var initial = observable();
  input.value = initial;
  observable.subscribe(function(){ input.value = observable(); });

  input.addEventListener('input', function() {
    observable(input.value);
  });
}

var aText = document.getElementById('a-text');
var bText = document.getElementById('b-text');
var cText = document.getElementById('c-text');

var a = observable(3), b = observable(2);
var c = computed(function(){ return a() + b(); }, [a, b]);

bindValue(aText, a);
bindValue(bText, b);
bindValue(cText, c);

2-way data binding

var aText = document.getElementById('a-text');
var bText = document.getElementById('b-text');
var cText = document.getElementById('c-text');

var a = observable(3), b = observable(2);
var c = computed(function(){ return a() + b(); }, [a, b]);

bindValue(aText, a);
bindValue(bText, b);
bindValue(cText, c);

2-way data binding

ko.bindingHandlers.numericValue = {
  init: function(element, valueAccessor) {
    var observable = valueAccessor();
    element.addEventListener('input', function() {
      var v = element.value;
      observable(isNaN(v = parseFloat(v)) ? 0 : v);
    });
  },
  update: function(element, valueAccessor) {
    element.value = ko.unwrap(valueAccessor());
  }
};

ko.applyBindings({
  a: ko.observable(3),
  b: ko.observable(2)
});
var aText = document.getElementById('a-text');
var bText = document.getElementById('b-text');
var cText = document.getElementById('c-text');

var a = observable(3), b = observable(2);
var c = computed(function(){ return a() + b(); }, [a, b]);

bindValue(aText, a);
bindValue(bText, b);
bindValue(cText, c);

Жизнь после фрейворков

Андрей Ваганов

e-mail: prostoandrei91@gmail.com

Twitter: prostoandrei

VK: prostoandrei

Presentation: http://slides.com/prostoandrei91/js

Made with Slides.com