Promisesy i Gulpowanie

Jakub Miziołek

O mnie

Front-end Developer w TT Lublin, Roche EnterpriseMobileApps, fanatyk Vima, Quake'a i długich dystansów

Plan produkcyjny na EE

  • Promise
  • Ciut o Gulp w ng

Promisy

Promise A/+ Logo

Promisy

pozwalają imitować/emulować synchroniczność w asynchronicznym środowisku JavaScript.

Codepen

link

See the Pen Pwzbqe by Jakub Miziołek (@jmiziolek) on CodePen.

Historia

  • 1976 Daniel P. Friedman, David Wise, Peter Hibbard pierwsze użycie terminu promise.
  • CommonJS Promise/A
  • jQuery Deferred Objects
  • Promise/A+

Po co one są!? Po co są one?!

callback hell
callbacks

Problem piekła callbacków

  • brak standaryzacji metod, argumentów...
  • brak gwarancji wywołania callbacka lub wywołania go tylko raz
  • potrzeba obsługi błędów na każdym poziomie zagnieżdżenia

Sposób działania

Promise reprezentuje wynik operacji. Może znajdować się w jednym z 3 stanów:

  • oczekujący
  • spełniony
  • odrzucony

Właściwości

Promise może zostać spełniony tylko raz. Raz spełniony/odrzucony promise nie może zmienić swojego stanu.

Właściwości

Do spełnienia lub odrzucenia promise'a możemy przypiąć dowolną ilość funkcji obsługi

Właściwości

Wynikiem jest zawsze pojedyńcza wartość. Wynik w przypadku odrzucenia nazywamy przyczyną

$q

Tworzenie


//defer, deferred, d, dfd...
var defer = $q.defer();
if(czy){
    defer.resolve("obiad");
} else {
    defer.reject("głód i halucynajce");
}
return defer.promise;
                    

Użycie


promise.then(ok, err);
//kazda z funkcji dostaje jeden argument jako wynik
                    

Callback vs Promise

Callback


var fs = require('fs');
function readJSON(filename, callback, errorcallback){
  fs.readFile(filename, function (err, res){
    if (err) return errorcallback(err);
    callback(res, function(){
        //i głębiej i głębiej i głębiej
    });
  });
}
readJSON('d.json', JSON.parse, console.error);
                    

Promise


var fs = require('q-io/fs');
fs.read('d.json').then(JSON.parse, console.error);
                    

Promise 2


var q = require('q');
var readFile = q.denodeify(require('fs').readFile);
readFile('d.json').then(JSON.parse, console.error);
                    

Łańcuch promisów


$http.get("nic")
    .then($http.post('dev/null'))
    .then(console.log, console.error);
                    

Dobre praktyki

funkcja obsługi odrzucenia zawsze na samym dole łańcucha!


x.then(dobraFoo)
    .then(rzucBledem)
    .then(dobraFoo)
    .then(null, console.error);
                    

Dobre praktyki

.done(), która przechwytuje wyjątki w przypadku braku obsługi odrzucenia


x.then(dobraFoo)
    .then(rzucBledem)
    .then(dobraFoo)
    .done();
                    

Promise w AngularJS

  • $q (uboga wersja kriskoval/q)
  • $timeout
  • $interval
  • $http
  • $resource
  • resolve route
  • angular-ui (modal)

Problemy

  • Zagnieżdzanie promisów
  • Konieczność częstego tworzenia nowych promisów lub korzystania z przystosowanych bibliotek

Promisy zagnieżdżone


getPralnie().then(function(pralnie){

    $scope.pralnie = pralnie;

    //zagnieżdżony promis
    $http.get('pralnia' + result._id).then(pierz);

});
                    

Promisy spłaszczone


getPralnie.then(function(pralnie){

    $scope.pralnie = pralnie;

    //rezultat zostanie przekazany do funkcji pierz
    return $http.get('pralnia' + result._id);

}).then(pierz);
                    

Szybkie tworzenie promisów


$q.when("zjadłem ostropest");
                    

tworzy promise rozwiązany przekazaną wartością


$q.reject("nie ma ostropestu");
                    

tworzy promise odrzucony przekazaną wartością

jQuery Defereds

kill it with fire!


                        $q($.ajax({/* ... */}));
                    

Dlaczego promisy są super?

  • jasne oddzielenie błędu od dobrego wyniku
  • łatwe łączenie wielu operacji
  • możliwość łączenia promisów jeden po drugim lub kilka na raz w jednym łańcuchu
  • są zawsze asynchroniczne
  • bubbling błędów

łączenie jeden po drugim


$http.get('janusz').then(sprawdzJanusza)
    .then(rozbierzJanusza)
    .then(utylizujKoszuleJanusza)
    .then(sprzatajOkruszki)
                    

łączenie równolegle


$http.get("posty");
$http.get("komenty");
$http.get("reklamy");
                    

łączenie równolegle cd…


$q.all([
    $http.get("posty"),
    $http.get("komenty"),
    $http.get("reklamy"),
]).then(results){
    //resutls = [posty, komenty, reklamy]
};
                    

łączenie równolegle cd…


$q.all([
    $http.get("posty"),
    $http.get("komenty"),
    $http.get("reklamy"),
]).spread(function(posty, komenty, reklamy){
    //argumenty rozdzielone wymaga $q-spread
});
                    

łączenie mieszane


$q.all([
    $http.get("posty"),
    $http.get("komenty").then(usunSpam),
    $http.get("reklamy"),
]).spread(function(posty, komentyPrzetworzone, reklamy){
    //argumenty rozdzielone
});
                    

zawsze asynchroniczne


console.log(1);
$q.when(3).then(console.log);
console.log(2);
//1,2,3
                    

bubbling błędów


$http.get("/users").then(zniszczIch)
    .then(ukryjZwłoki)
    .then(null, uciekajPrzedPolicją);
  }); 
                    

Routing


//ngRoute albo ui-router
$stateProvider.state('login', {
    url: '/login',
    templateUrl: 'views/login.html',
    controller: 'LoginController',
}).state('index', {
    url: '/index',
    templateUrl: 'views/main.html',
    controller: 'MainController',
    resolve: {
        lista: function(lista){
            return lista.get();
        }
    },
});
                    

Codepen

link

See the Pen Pwzbqe by Jakub Miziołek (@jmiziolek) on CodePen.

progress/notify


function processMartix(data){
  var output = [],
      deferred = $q.defer(),
      percentComplete = 0;

  for(var i = 0; i < data.length; i++){
    output.push(processDataItem(data[i]));
    percentComplete = (i+1)/data.length * 100;
    deferred.notify(percent);
  }

  deferred.resolve(output);

  return deferred.promise;
};

processMartix(data)
  .then(function(result){
    // success
  }, function(error){
    // error
  }, function(percent){
    $scope.progress = percent;
  }); 
                    

GULP

steaming build system

Przeznaczenie

  • konkatenacja/minifikacja css,js,html
  • kompilacja Sass, CoffeeScript, itd.
  • LiveReload
  • Deployment

Przesiadka z Grunta?

Zalety gulpa:

  • kod zamiast konfiguracji
  • szybkość działania
  • minium IO, maximum współbierzności
  • Tylko 5 metod(src, dest, task, watch, run)
  • można używać zwykłych modułów zamiast pluginów
  • wspaniała nazwa, mniej przyziemna

src(files)

Strumień odczytu

dest(folder)

Strumień zapisu

task(name, [deps], foo)

Rejestracja taska. Potem jest on dostępny z konsoli i jako zależność innych tasków

watch(files, foo)

Zrób coś jak zmieni się coś w tych plikach

run(name)

Uruchom zadanie


gulp.task('angularcache', function(){
    //make templateCache
    return gulp.src('./frontend/build/views/*.html')
    .pipe(templateCache("templates.js", {module: "ttApp", root: "views/"}))
    .pipe(gulp.dest('frontend/app/scripts/'));
});

//wynik
angular.module("ttApp").run(["$templateCache", function($templateCache) {
$templateCache.put("views/przyklad.html"," html ");
};
                    

Linki

Dzięki!

Jakieś pytania?