Loading…

Flash Player 9 (or above) is needed to view presentations.
We have detected that you do not have it on your computer. To install it, go here.

Like this presentation? Why not share!

Like this? Share it with your network

Share

JavaScript Event-driven architecture

on

  • 3,869 views

 

Statistics

Views

Total Views
3,869
Views on SlideShare
3,830
Embed Views
39

Actions

Likes
6
Downloads
67
Comments
0

2 Embeds 39

http://cloud.aylesbury.ac.uk 38
http://twitter.com 1

Accessibility

Categories

Upload Details

Uploaded via as Apple Keynote

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />

JavaScript Event-driven architecture Presentation Transcript

  • 1. JavaScript event-driven architecture Радослав Станков OpenFest 2010
  • 2. Кой съм аз? @rstankov http://rstankov.com http://blog.rstankov.com http://github.com/rstankov
  • 3. Какво е Event-driven architecture?
  • 4. Демонстрация
  • 5. <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>OpenFest Demo</title> <link href="/application.css" media="screen" rel="stylesheet" type="text/css" /> </head> <body> <div id="images_widget"> <form method="post" action="/images" enctype="multipart/form-data" id="new_image"> <input type="file" id="image_file" name="image[file]" /> <input type="submit" value="Добави снимка" /> </form> <ol> <li> <div style="background-image: url(/system/images/2/thumb.png);"></div> <span> <a href="/system/images/2/big.png" target="_blank" class="view">Преглед</a> <a href="/images/2" rel="nofollow" class="delete">Изтрий</a> </span> </li> <!-- more items --> </ol> </div> </body> </html>
  • 6. <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>OpenFest Demo</title> <link href="/application.css" media="screen" rel="stylesheet" type="text/css" /> </head> <body> <div class="question"> <h1>Сигурни ли сте, че искате да изтриете тази снимка?</h1> <p> <img alt="Thumb" src="/system/images/1/thumb.png" /> </p> <form method="post" action="/images"> <input type="hidden" name="_method" value="delete" /> <input type="submit" value="Да" /> <a href="/images">Не</a> </form> </div> </body> </html>
  • 7. <form method="post" action="/images" enctype="multipart/form-data" id="new_image"> <input type="file" id="image_file" name="image[file]" /> <input type="submit" value="Добави снимка" /> </form>
  • 8. $.fileUploadSupported && $('#new_image').submit(function(e){ var form = $(this), file = form.children('input[type="file"]'), files = file[0].files; if (files && files.length > 0){ $.uploadFile({ url: form.attr("action"), dataType: "html", name: file.attr("name"), beforeSend: function(){ /* disable form */ }, complete: function(){ /* enable form */ }, error: function(xhr){ xhr.status == 422 && alert(xhr.responseText); }, success: function (html){ $("#images_widget ol").prepend(html); }, }, files[0]); } this.reset(); return false; });
  • 9. $.fileUploadSupported && $('#new_image').submit(function(e){ var form = $(this), file = form.children('input[type="file"]'), files = file[0].files; if (files && files.length > 0){ $.uploadFile({ url: form.attr("action"), dataType: "html", name: file.attr("name"), beforeSend: function(){ /* disable form */ }, complete: function(){ /* enable form */ }, error: function(xhr){ xhr.status == 422 && alert(xhr.responseText); }, success: function (html){ $("#images_widget ol").prepend(html); }, }, files[0]); } this.reset(); return false; });
  • 10. $.fileUploadSupported && $('#new_image').submit(function(e){ var form = $(this), file = form.children('input[type="file"]'), files = file[0].files; if (files && files.length > 0){ $.uploadFile({ url: form.attr("action"), dataType: "html", name: file.attr("name"), beforeSend: function(){ /* disable form */ }, complete: function(){ /* enable form */ }, error: function(xhr){ xhr.status == 422 && alert(xhr.responseText); }, success: function (html){ $("#images_widget ol").prepend(html); }, }, files[0]); } this.reset(); return false; });
  • 11. $.fileUploadSupported && $('#new_image').submit(function(e){ var form = $(this), file = form.children('input[type="file"]'), files = file[0].files; if (files && files.length > 0){ $.uploadFile({ url: form.attr("action"), dataType: "html", name: file.attr("name"), beforeSend: function(){ /* disable form */ }, complete: function(){ /* enable form */ }, error: function(xhr){ xhr.status == 422 && form.trigger("action:error", xhr.responseText); }, success: function (html){ form.trigger("action:insert", html); }, }, files[0]); } this.reset(); return false; });
  • 12. $("#images_widget").each(function(){ var widget = $(this), images = element.children("ol"); element.bind("action:insert", function(e, content){ images.prepend(content); }); element.bind("action:error", function(e, errorMessage){ alert(errorMessage); }); });
  • 13. <li> <div style="background-image: url(...);"></div> <span> <a href="..." class="view">Преглед</a> <a href="..." class="delete">Изтрий</a> </span> </li>
  • 14. <li> <div style="background-image: url(...);"></div> <span> <a href="..." class="view">Преглед</a> <a href="..." class="delete" data-method="delete" data-confirm="."> Изтрий </a> </span> </li>
  • 15. <li> <div style="background-image: url(...);"></div> <span> <a href="..." class="view">Преглед</a> <a href="..." class="delete" data-method="delete" data-confirm="."> Изтрий </a> </span> </li>
  • 16. $("#images_widget").each(function(){ // ... code ... widget.delegate('[data-method="delete"]', "click", function(e){ e.preventDefault(); var element = $(this); if (confirm(element.data("confirm"))){ $.ajax({ url: element.attr("href"), type: "DELETE" }); element.parent("li").remove(); } }); };
  • 17. <span> <a href="..." class="view">Преглед</a> <a href="..." class="delete" data-method="delete" data-confirm="."> Изтрий </a> </span>
  • 18. <span> <a href="..." class="view" data-action="preview">Преглед</a> <a href="..." class="delete" data-method="delete" data-confirm="."> Изтрий </a> </span>
  • 19. <span> <a href="..." class="view" data-action="preview">Преглед</a> <a href="..." class="delete" data-method="delete" data-confirm="."> Изтрий </a> </span>
  • 20. $("#images_widget").each(function(){ // ... code ... widget.delegate('[data-action="preview"]', "click", function(e){ e.preventDefault(); preview($(this).attr("href")); }); }; function preview(url){ // ... code ... }
  • 21. <ol> <li><!-- image --></li> <li><!-- image --></li> <li><!-- image --></li> </ol>
  • 22. <ol data-sortable-url="/images/reorder"> <li id="image_3"><!-- image --></li> <li id="image_2"><!-- image --></li> <li id="image_1"><!-- image --></li> </ol>
  • 23. <ol data-sortable-url="/images/reorder"> <li id="image_3"><!-- image --></li> <li id="image_2"><!-- image --></li> <li id="image_1"><!-- image --></li> </ol>
  • 24. <ol data-sortable-url="/images/reorder"> <li id="image_3"><!-- image --></li> <li id="image_2"><!-- image --></li> <li id="image_1"><!-- image --></li> </ol>
  • 25. $("#images_widget").each(function(){ // ... code ... images.sortable({ placeholder: "ui-state-highlight", update: function(e, ui){ $.ajax({ url: images.data("sortable-url"), type: "PUT", data: $(this).sortable("serialize") }); } }); });
  • 26. $("#images_widget").each(function(){ var widget = $(this), images = widget.children("ol"); widget.bind("action:insert", function(e, content){ images.prepend(content); }); widget.bind("action:error", function(e, errorMessage){ alert(errorMessage); }); widget.delegate('[data-method="delete"]', "click", function(e){ e.preventDefault(); var element = $(this); if (confirm(element.data("confirm"))){ $.ajax({ url: element.attr("href"), type: "DELETE" }); element.remove(); } }); widget.delegate('[data-action="preview"]', "click", function(e){ e.preventDefault(); preview($(this).attr("href")); }); images.sortable({ placeholder: "ui-state-highlight", update: function(e, ui){ $.ajax({ url: images.data("sortable-url"), type: "PUT", data: $(this).sortable("serialize") }); } }); });
  • 27. $("#images_widget").each(function(){ var widget = $(this), images = widget.children("ol"); widget.bind("action:insert", function(e, content){ images.prepend(content); }); widget.bind("action:error", function(e, errorMessage){ alert(errorMessage); }); widget.delegate('[data-method="delete"]', "click", function(e){ e.preventDefault(); var element = $(this); if (confirm(element.data("confirm"))){ $.ajax({ url: element.attr("href"), type: "DELETE" }); element.remove(); } }); widget.delegate('[data-action="preview"]', "click", function(e){ e.preventDefault(); preview($(this).attr("href")); }); images.sortable({ placeholder: "ui-state-highlight", update: function(e, ui){ $.ajax({ url: images.data("sortable-url"), type: "PUT", data: $(this).sortable("serialize") }); } }); });
  • 28. $("#images_widget").each(function(){ var widget = $(this), images = widget.children("ol"); widget.bind("action:insert", function(e, content){ images.prepend(content); }); widget.bind("action:error", function(e, errorMessage){ alert(errorMessage); }); widget.delegate('[data-method="delete"]', "click", function(e){ e.preventDefault(); var element = $(this); if (confirm(element.data("confirm"))){ $.ajax({ url: element.attr("href"), type: "DELETE" }); element.remove(); } }); widget.delegate('[data-action="preview"]', "click", function(e){ e.preventDefault(); preview($(this).attr("href")); }); images.sortable({ placeholder: "ui-state-highlight", update: function(e, ui){ $.ajax({ url: images.data("sortable-url"), type: "PUT", data: $(this).sortable("serialize") }); } }); });
  • 29. $("#images_widget").each(function(){ // ... code ... widget.bind("action:error", function(e, errorMessage){ alert(errorMessage); }); widget.delegate('[data-action="preview"]', "click", function(e){ e.preventDefault(); preview($(this).attr("href")); }); });
  • 30. $(document).bind("action:error", function(e, errorMessage){ alert(errorMessage); }); $(document).delegate('[data-action="preview"]', "click", function(e){ e.preventDefault(); preview($(this).attr("href")); });
  • 31. $("#images_widget").each(function(){ var widget = $(this), images = widget.children("ol"); widget.bind("action:insert", function(e, content){ images.prepend(content); }); widget.delegate('[data-method="delete"]', "click", function(e){ e.preventDefault(); var element = $(this); if (confirm(element.data("confirm"))){ $.ajax({ url: element.attr("href"), type: "DELETE" }); element.remove(); } }); images.sortable({ placeholder: "ui-state-highlight", update: function(e, ui){ $.ajax({ url: images.data("sortable-url"), type: "PUT", data: $(this).sortable("serialize") }); } }); });
  • 32. $("#images_widget").each(function(){ var widget = $(this), images = widget.children("ol"); widget.bind("action:insert", function(e, content){ images.prepend(content); }); widget.delegate('[data-method="delete"]', "click", function(e){ e.preventDefault(); var element = $(this); if (confirm(element.data("confirm"))){ $.ajax({ url: element.attr("href"), type: "DELETE" }); element.remove(); } }); images.sortable({ placeholder: "ui-state-highlight", update: function(e, ui){ $.ajax({ url: images.data("sortable-url"), type: "PUT", data: $(this).sortable("serialize") }); } }); });
  • 33. $("#images_widget").each(function(){ // ... code ... widget.delegate('[data-method="delete"]', "click", function(e){ e.preventDefault(); var element = $(this); if (confirm(element.data("confirm"))){ $.ajax({ url: element.attr("href"), type: "DELETE" }); element.remove(); } }); });
  • 34. $(document).delegate('[data-method="delete"]', "click", function(e){ e.preventDefault(); var element = $(this); if (confirm(element.data("confirm"))){ $.ajax({ url: element.attr("href"), type: "DELETE" }); element.trigger("action:delete"); } });
  • 35. $("#images_widget").each(function(){ // ... code ... widget.delegate('[data-method="delete"]', "click", function(e){ e.preventDefault(); var element = $(this); if (confirm(element.data("confirm"))){ $.ajax({ url: element.attr("href"), type: "DELETE" }); element.remove(); } }); });
  • 36. $("#images_widget").each(function(){ // ... code ... widget.delegate("li", "action:delete", function(){ $(this).remove(); }); });
  • 37. $("#images_widget").each(function(){ var widget = $(this), images = widget.children("ol"); widget.bind("action:insert", function(e, content){ images.prepend(content); }); widget.delegate("li", "action:delete", function(){ $(this).remove(); }); images.sortable({ placeholder: "ui-state-highlight", update: function(e, ui){ $.ajax({ url: images.data("sortable-url"), type: "PUT", data: $(this).sortable("serialize") }); } }); });
  • 38. $("#images_widget").each(function(){ var widget = $(this), images = widget.children("ol"); widget.bind("action:insert", function(e, content){ images.prepend(content); }); widget.delegate("li", "action:delete", function(){ $(this).remove(); }); images.sortable({ placeholder: "ui-state-highlight", update: function(e, ui){ $.ajax({ url: images.data("sortable-url"), type: "PUT", data: $(this).sortable("serialize") }); } }); });
  • 39. $("#images_widget").each(function(){ // ... code ... images.sortable({ placeholder: "ui-state-highlight", update: function(e, ui){ $.ajax({ url: images.data("sortable-url"), type: "PUT", data: $(this).sortable("serialize") }); } }); });
  • 40. $("#images_widget").each(function(){ // ... code ... images.sortable({ placeholder: "ui-state-highlight", update: function(e, ui){ images.trigger("action:reorder", $(this).sortable("serialize")); } }); });
  • 41. $(document).delegate("[data-sortable-url]", "action:reorder", function(e, data){ $.ajax({ url: $(this).data("sortable-url"), type: "PUT", data: data }); });
  • 42. $("#images_widget").each(function(){ var widget = $(this), images = widget.children("ol"); widget.bind("action:insert", function(e, content){ images.prepend(content); }); widget.delegate("li", "action:delete", function(){ $(this).remove(); }); images.sortable({ placeholder: "ui-state-highlight", update: function(e, ui){ images.trigger("action:reorder", $(this).sortable("serialize")); } }); });
  • 43. $("#images_widget").each(function(){ var widget = $(this), images = widget.children("ol"); widget.bind("action:insert", function(e, content){ images.prepend(content); }); widget.delegate("li", "action:delete", function(){ $(this).remove(); }); images.sortable({ placeholder: "ui-state-highlight", update: function(e, ui){ images.trigger("action:reorder", $(this).sortable("serialize")); } }); });
  • 44. $("#images_widget").each(function(){ var widget = $(this), images = widget.children("ol"); widget.bind("action:insert", function(e, content){ images.prepend(content); }); widget.delegate("li", "action:delete", function(){ $(this).remove(); }); images.sortable({ placeholder: "ui-state-highlight", update: function(e, ui){ images.trigger("action:reorder", $(this).sortable("serialize")); } }); });
  • 45. $("#images_widget").each(function(){ var widget = $(this), images = widget.children("ol"); widget.bind("action:insert", function(e, content){ images.prepend(content); }); widget.delegate("li", "action:delete", function(){ $(this).remove(); }); images.sortable({ placeholder: "ui-state-highlight", update: function(e, ui){ images.trigger("action:reorder", $(this).sortable("serialize")); } }); });
  • 46. $("#images_widget").each(function(){ var widget = $(this), images = widget.children("ol"); widget.bind("action:insert", function(e, content){ images.prepend(content); }); widget.delegate("li", "action:delete", function(){ $(this).remove(); }); images.sortable({ placeholder: "ui-state-highlight", update: function(e, ui){ images.trigger("action:reorder", $(this).sortable("serialize")); } }); });
  • 47. $("#images_widget").each(function(){ var widget = $(this), images = widget.children("ol"); widget.bind("action:insert", function(e, content){ images.prepend(content); }); widget.delegate("li", "action:delete", function(){ $(this).remove(); }); images.sortable({ placeholder: "ui-state-highlight", update: function(e, ui){ images.trigger("action:reorder", $(this).sortable("serialize")); } }); });
  • 48. var OpenFest = { createDynamicWidget: function(widget, opts){ widget = $(widget); opts = jQuery.extend({ list: "ol", item: "li" }, opts || {}); var list = widget.children(opts.list); widget.bind("action:insert", function(e, content){ list.prepend(content); }); widget.delegate(opts.item, "action:delete", function(){ $(this).remove(); }); list.sortable({ placeholder: "ui-state-highlight", update: function(e, ui){ list.trigger("action:reorder", $(this).sortable("serialize")); } }); } };
  • 49. OpenFest.createDynamicWidget("#images_widget");
  • 50. $("#images_widget").dynamicWidget();
  • 51. $(document).bind("action:error", function(e, errorMessage){ alert(errorMessage); }); $(document).delegate('[data-action="preview"]', "click", function(e){ e.preventDefault(); preview($(this).attr("href")); }); $(document).delegate('[data-method="delete"]', "click", function(e){ e.preventDefault(); var element = $(this); if (confirm(element.data("confirm"))){ $.ajax({ url: element.attr("href"), type: "DELETE" }); element.trigger("action:delete"); } });
  • 52. $(document).bind("action:error", function(e, errorMessage){ alert(errorMessage); }); $(document).delegate('[data-action="preview"]', "click", function(e){ e.preventDefault(); preview($(this).attr("href")); }); $(document).delegate('[data-method="delete"]', "click", function(e){ e.preventDefault(); var element = $(this); if (confirm(element.data("confirm"))){ $.ajax({ url: element.attr("href"), type: "DELETE" }); element.trigger("action:delete"); } });
  • 53. $(document).bind("action:error", function(e, errorMessage){ alert(errorMessage); }); $(document).delegate('[data-action="preview"]', "click", function(e){ e.preventDefault(); preview($(this).attr("href")); }); $(document).delegate('[data-method="delete"]', "click", function(e){ e.preventDefault(); var element = $(this); if (confirm(element.data("confirm"))){ $.ajax({ url: element.attr("href"), type: "DELETE" }); element.trigger("action:delete"); } });
  • 54. $(document).bind("action:error", function(e, errorMessage){ alert(errorMessage); }); $(document).delegate('[data-action="preview"]', "click", function(e){ e.preventDefault(); preview($(this).attr("href")); }); $(document).delegate('[data-method="delete"]', "click", function(e){ e.preventDefault(); var element = $(this); if (confirm(element.data("confirm"))){ $.ajax({ url: element.attr("href"), type: "DELETE" }); element.trigger("action:delete"); } });
  • 55. var OpenFest = { createDynamicWidget: function(){ /* code */ }, confirm: function(question){ return !question || confirm(question); }, errorMessage: function(errorMessage){ alert(errorMessage); }, preview: function(){ /* code */ } };
  • 56. $(document).bind("action:error", function(e, errorMessage){ alert(errorMessage); }); $(document).delegate('[data-action="preview"]', "click", function(e){ e.preventDefault(); preview($(this).attr("href")); }); $(document).delegate('[data-method="delete"]', "click", function(e){ e.preventDefault(); var element = $(this); if (confirm(element.data("confirm"))){ $.ajax({ url: element.attr("href"), type: "DELETE" }); element.trigger("action:delete"); } });
  • 57. $(document).bind("action:error", function(e, errorMessage){ OpenFest.errorMessage(errorMessage); }); $(document).delegate('[data-action="preview"]', "click", function(e){ e.preventDefault(); OpenFest.preview($(this).attr("href")); }); $(document).delegate('[data-method="delete"]', "click", function(e){ e.preventDefault(); var element = $(this); if (OpenFest.confirm(element.data("confirm"))){ $.ajax({ url: element.attr("href"), type: "DELETE" }); element.trigger("action:delete"); } });
  • 58. //= require "jquery/core" //= require "jquery/ui" //= require "jquery/html5_upload" //= require "open_fest" //= require "behaviors/error" //= require "behaviors/delete" //= require "behaviors/preview" //= require "behaviors/reorder" OpenFest.createDynamicWidget("#images_widget"); $.fileUploadSupported && $('#new_image').submit(function(e){ // ... the ugly code ... });
  • 59. Кода стъпка по стъпка: https://github.com/RStankov/OpenFest-2010/
  • 60. Какво е Event-driven architecture? Основната идея, е да разделите приложeнието си на малки независими части, които не знаят еднa за другa и контактуват помежду си чрез предаване на събития.
  • 61. Няколко полезни съвета
  • 62. Няколко полезни съвета • вашите модули да са изолирани и да контактуват само чрез събития
  • 63. Няколко полезни съвета • вашите модули да са изолирани и да контактуват само чрез събития • следвайте един модел на именуване на събитията и data-* атрибутите си
  • 64. Няколко полезни съвета • вашите модули да са изолирани и да контактуват само чрез събития • следвайте един модел на именуване на събитията и data-* атрибутите си • колкото по-общо е едно събитие толкова по-високо в йерархията трябва да е
  • 65. Няколко полезни съвета • вашите модули да са изолирани и да контактуват само чрез събития • следвайте един модел на именуване на събитията и data-* атрибутите си • колкото по-общо е едно събитие толкова по-високо в йерархията трябва да е • използвайте често делегиране на събития
  • 66. Няколко полезни съвета • вашите модули да са изолирани и да контактуват само чрез събития • следвайте един модел на именуване на събитията и data-* атрибутите си • колкото по-общо е едно събитие толкова по-високо в йерархията трябва да е • използвайте често делегиране на събития • използвайте кратки и бързи selector-и при делегиране на събития
  • 67. Няколко полезни съвета • вашите модули да са изолирани и да контактуват само чрез събития • следвайте един модел на именуване на събитията и data-* атрибутите си • колкото по-общо е едно събитие толкова по-високо в йерархията трябва да е • използвайте често делегиране на събития • използвайте кратки и бързи selector-и при делегиране на събития • предефинирайте действията на потребителя
  • 68. Няколко полезни съвета • вашите модули да са изолирани и да контактуват само чрез събития • следвайте един модел на именуване на събитията и data-* атрибутите си • колкото по-общо е едно събитие толкова по-високо в йерархията трябва да е • използвайте често делегиране на събития • използвайте кратки и бързи selector-и при делегиране на събития • предефинирайте действията на потребителя • внимавайте с често повтарящи се събития като mousemove, keyup
  • 69. Няколко полезни съвета • вашите модули да са изолирани и да контактуват само чрез събития • следвайте един модел на именуване на събитията и data-* атрибутите си • колкото по-общо е едно събитие толкова по-високо в йерархията трябва да е • използвайте често делегиране на събития • използвайте кратки и бързи selector-и при делегиране на събития • предефинирайте действията на потребителя • внимавайте с често повтарящи се събития като mousemove, keyup • следвайте добрите практики за писане на JavaScript
  • 70. Няколко полезни съвета • вашите модули да са изолирани и да контактуват само чрез събития • следвайте един модел на именуване на събитията и data-* атрибутите си • колкото по-общо е едно събитие толкова по-високо в йерархията трябва да е • използвайте често делегиране на събития • използвайте кратки и бързи selector-и при делегиране на събития • предефинирайте действията на потребителя • внимавайте с често повтарящи се събития като mousemove, keyup • следвайте добрите практики за писане на JavaScript • тествайте!
  • 71. Какво харесвам в този начин на работа?
  • 72. Какво харесвам в този начин на работа? • JavaScript е направен да работи по подобен начин
  • 73. Какво харесвам в този начин на работа? • JavaScript е направен да работи по подобен начин • Пише се сравнително малко код с висока честота на пре-използваемост
  • 74. Какво харесвам в този начин на работа? • JavaScript е направен да работи по подобен начин • Пише се сравнително малко код с висока честота на пре-използваемост • Лесно се сменят различните части от приложението
  • 75. Какво харесвам в този начин на работа? • JavaScript е направен да работи по подобен начин • Пише се сравнително малко код с висока честота на пре-използваемост • Лесно се сменят различните части от приложението • Точно изразен начин, по който комуникират частите на приложението
  • 76. Какво харесвам в този начин на работа? • JavaScript е направен да работи по подобен начин • Пише се сравнително малко код с висока честота на пре-използваемост • Лесно се сменят различните части от приложението • Точно изразен начин, по който комуникират частите на приложението • Лесно тестване
  • 77. Благодаря за вниманието @rstankov