Napište lepší JavaScript se sliby

Pravděpodobně jste slyšeli řeči kolem vodního chladiče o tom, jak jsou sliby budoucností. Používají je všechny skvělé děti, ale vy nevidíte, co je dělá tak výjimečnými. Nemůžeš prostě použít zpětné volání? Co je velký problém? V tomto článku se podíváme na to, co jsou sliby a jak je můžete využít k psaní lepšího JavaScriptu.

Sliby jsou snadněji čitelné

Řekněme, že chceme získat nějaká data z HipsterJesus API a přidat je na naši stránku. Toto rozhraní API odpovídá daty, která vypadají takto:

{
  "text": "<p>Lorem ipsum...</p>",
  "params": {
    "paras": 4,
    "type": "hipster-latin"
  }
}

Pomocí zpětného volání bychom napsali něco takového:

$.getJSON('http://hipsterjesus.com/api/', function(data) {
  $('body').append(data.text);
});

Pokud máte zkušenosti s jQuery, víte, že vytváříme GET požadavek a očekávání JSON v těle odpovědi. Také předáváme funkci zpětného volání, která vezme odpověď JSON a přidá ji do dokumentu.

Dalším způsobem, jak to napsat, je použít objekt slibu vrácený getJSON metoda. K tomuto objektu můžete přímo připojit zpětné volání.

var promise = $.getJSON('http://hipsterjesus.com/api/');

promise.done(function(data) {
  $('body').append(data.text);
});

Stejně jako v příkladu zpětného volání se připojí výsledek požadavku API k dokumentu, když je požadavek úspěšný. Co se ale stane, když žádost selže? Můžeme také připojit fail handler k našemu slibu.

var promise = $.getJSON('http://hipsterjesus.com/api/');

promise.done(function(data) {
  $('body').append(data.text);
});

promise.fail(function() {
  $('body').append('

Oh no, something went wrong!

'); });

Většina lidí odstraní promise proměnná, díky čemuž je na první pohled o něco snazší zjistit, co kód dělá.

$.getJSON('http://hipsterjesus.com/api/')

.done(function(data) {
  $('body').append(data.text);
})

.fail(function() {
  $('body').append('

Oh no, something went wrong!

'); });

jQuery také obsahuje always obsluha události, která je volána bez ohledu na to, zda požadavek uspěje nebo selže.

$.getJSON('http://hipsterjesus.com/api/')

.done(function(data) {
  $('body').append(data.text);
})
.fail(function() {
  $('body').append('

Oh no, something went wrong!

'); }) .always(function() { $('body').append('

I promise this will always be added!.

'); });

Se sliby je respektováno pořadí zpětných volání. Zaručujeme, že máme naše done nejprve volané zpětné volání, poté naše fail zpětné volání a nakonec naše always zpětné volání.

Lepší rozhraní API

Řekněme, že chceme vytvořit obalový objekt pro HipsterJesus API. Přidáme metodu html , abyste vrátili data HTML, která pocházejí z API. Namísto toho, aby tato metoda přebírala obslužnou rutinu, která je volána, když je požadavek vyřešen, můžeme nechat metodu vrátit objekt slíbení.

var hipsterJesus = {
  html: function() {
    return $.getJSON('http://hipsterjesus.com/api/').then(function(data) {
      return data.text;
    });
  }
};

Skvělé na tom je, že můžeme obcházet náš slibovaný předmět, aniž bychom se museli starat o to, kdy nebo jak vyřeší svou hodnotu. Jakýkoli kód, který potřebuje návratovou hodnotu příslibu, může pouze zaregistrovat zpětné volání s done .

then metoda nám umožňuje upravit výsledek příslibu a předat jej dalšímu handleru v řetězci. To znamená, že nyní můžeme naše nové API používat takto:

hipsterJesus.html().done(function(html) {
  $("body").append(html);
});

Až donedávna bylo jednou ze zabijáckých vlastností AngularJS to, že šablony se mohly přímo vázat na sliby. V ovladači Angular to vypadalo takto:

$scope.hipsterIpsum = $http.get('http://hipsterjesus.com/api/');

Pak to bylo stejně jednoduché jako napsat {{ hipsterIpsum.text }} v šabloně. Když se slib vyřeší, Angular automaticky aktualizuje pohled. Bohužel tým Angular tuto funkci zavrhl. Prozatím ji lze aktivovat voláním $parseProvider.unwrapPromises(true) . Doufám, že Angular a další frameworky budou tuto funkci do budoucna zahrnovat (koukám na tebe Ember).

Řetězení

Nejlepší na slibech je, že je můžete řetězit! Řekněme, že chceme do našeho API přidat metodu, která vrací pole odstavců.

var hipsterJesus = {

  html: function() {
    return $.getJSON('http://hipsterjesus.com/api/').then(function(data) {
      return data.text;
    });
  },

  paragraphs: function() {
    return this.html().then(function(html) {
      return html.replace(/<[^>]+>/g, "").split("");
    });
  }
};

Naši metodu HTML jsme nechali stejnou a používáme ji v paragraphs metoda. Protože návratová hodnota zpětného volání příslibu je předána dalšímu zpětnému volání v řetězci, můžeme vytvářet malé, funkční metody, které mění data tak, jak jimi prochází.

Sliby můžeme řetězit, kolikrát chceme. Přidejme metodu pro věty.

var hipsterJesus = {

  html: function() {
    return $.getJSON('http://hipsterjesus.com/api/').then(function(data) {
      return data.text;
    });
  },

  paragraphs: function() {
    return this.html().then(function(html) {
      return html.replace(/<[^>]+>/g, "").split("");
    });
  },

  sentences: function() {
    return this.paragraphs().then(function(paragraphs) {
      return [].concat.apply([], paragraphs.map(function(paragraph) {
        return paragraph.split(/. /);
      }));
    });
  }
};

Více hovorů

Pravděpodobně nejpozoruhodnější vlastností slibů je schopnost kombinovat více volání API. Když používáte zpětná volání, co se stane, když potřebujete provést dvě volání API najednou? Pravděpodobně nakonec napíšete něco takového:

var firstData = null;
var secondData = null;

var responseCallback = function() {

  if (!firstData || !secondData)
    return;

  // do something
}

$.get("http://example.com/first", function(data) {
  firstData = data;
  responseCallback();
});

$.get("http://example.com/second", function(data) {
  secondData = data;
  responseCallback();
});

Se sliby je to mnohem jednodušší:

var firstPromise = $.get("http://example.com/first");
var secondPromise = $.get("http://example.com/second");

$.when(firstPromise, secondPromise).done(function(firstData, secondData) {
  // do something
});

Zde používáme when metoda pro připojení obslužné rutiny, která se zavolá, když jsou provedeny oba požadavky.

Závěr

A je to! Doufejme, že máte smysl pro některé úžasné věci, kterých můžete dosáhnout pomocí slibů. Jaký je váš oblíbený způsob, jak je používat? Dejte mi vědět v komentářích!

*Poznámka:Pro jednoduchost tento článek používá odloženou implementaci jQuery. Mezi Deferred jQuery jsou jemné rozdíly objekt a specifikace Promises/A+, což je kanonický standard. Pro více informací se podívejte na Q's Coming z jQuery wiki.