2012-07-20

מקביליות עם jQuery (ובכלל)

בפוסט זה אעסוק בשינוי מרכזי שנעשה ל jQuery בנושא המקביליות. אמנם מדובר בשינוי ספציפי של jQuery, אבל ניתן ללמוד משינוי זה גם לקחים שנוגעים לשפות אחרות וצד-השרת.

ה"מקושרים" שבכם, אלו שקוראים הרבה חדשות טכנולוגיות, בוודאי שמעו כבר על כמה שינויים שהוכרזו ע"י jQuery לאחרונה:
  • היכולת לארוז רק חלקים מהספרייה (אולי בגלל התחרות מ Zepto.js).
  • הפסקת התמיכה בגרסאות לא-חדשות של Internet Explorer.
  • איחוד מנגנוני הרישום לאירועים: bind, live ו delegate למנגנון ה on (חדשות ישנות יותר).

האמת שמדובר בשינוי שהוצג ב jQuery גרסה 1.5 (עם כמה תוספות ב 1.6 ו 1.7) - ואישית, אני לא זוכר שהוא עשה חצי מהמהומה של השינויים הנ"ל. בכל זאת זהו שינוי משמעותי וחשוב.

השינוי נוגע באזור ה Ajax ומאפשר גמישות שלא הייתה קיימת קודם לכן.

בואו נדבר עליו.


שייך לסדרה מבוא מואץ ל JavaScript ו jQuery




שינוי בפקודת ה Ajax
למי שלא מכיר, jQuery עוטף את ה XMLHttpRequest (או בקיצור XHR) של הדפדפן בצורה נוחה ומאפשר לקרוא בפשטות ajax.$ על מנת לבצע קריאת ajax. יש גם גרסאות מקוצרות בשם get.$ ו post.$.

עד גרסה 1.4 הדרך לבצע קריאת ajax הייתה כזו:
$.get('http://server.com/myurl', {
  success: onSuccess, // a callback function to be triggered on success
  failure: onFailure, // a callback function to be triggered on failure
  always: onAlways // a callback function that is triggered on either failure of success. Like "finally".
});

success, failure ו always הם callbacks שנקראים כאשר הקריאה מסתיימת, הצלחה או כישלון.

מגרסה 1.5 אפשר לכתוב את הקוד בדרך הבאה:
var request = $.get('http://server.com/myurl');
...
request.done(onSuccess);
request.fail(onFailure);
request.always(onAlways);

כלומר, ניתן לבחור אלו פונקציות (callback) יקראו בעקבות התשובה לאחר שהקריאה התבצעה. אם התשובה כבר חזרה, הקריאה (done, למשל) תפעיל את פונקציית ה callback מיידית.

מה הטעם? האם הקוד הקודם לא נראה יותר ישיר ופשוט?
יש עוצמה רבה בכך ש"הכל על השולחן" וברור לי במקום אחד מה היא הבקשה שנשלחת ומה קורה בעת החזרה. מדוע לסבך?

ההבדל הוא בין תוכנות קטנות, בהן הצורה הראשונה היא טובה למדי, ותוכנות גדולות יותר בהן הצורה הראשונה הופכת למסורבלת. לפני שניגש לבחון את השימוש בפועל, אני רוצה להסביר קצת יותר טוב את ההתנהגות של צורת הכתיבה החדשה.


Making Promises
אפתח בכמה מילים גדולות: מה ש jQuery עשו, הוא לממש Design Pattern (יו... וואהו!) שידוע בשמות הבאים: Deferred Object או Promise או Future. יש אפילו הגדרה פורמלית בשם Promises/A שמגדירה כיצד תבנית זו אמורה להתנהג בג'אווהסקריפט.
לאכזבתם של לא-מעטים, jQuery לא נצמדה ל"הגדרה הפורמלית" ומימשה וריאציה קצת שונה של תבנית העיצוב, מימוש שהושפע כנראה מספריית Dojo שסיפקה יכולת דומה. אם אתם אורתודוקסים ל Promises/A, תוכלו למצוא מימושים "תקניים" בספריות כגון Q.js או Async.js שניתן להשתמש שהם. לרובנו, כל מה ש jQuery יעשו - מהווה את התקן בפועל.

על מנת להבין את המשמעות של הפעולה של ה Promise, נפרק אותה (Deconstruct) למרכיבים יותר בסיסים ונבחן אותם. הביטו על קוד ה JavaScript/jQuery הבא:
var deferred = new $.Deferred();
deferred.done(function(){ console.log('done'); }); 
deferred.fail(function(){ console.log('fail'); }); 
...
deferred.done(function(){ console.log('donedone'); }); 

האובייקט Deferred הוא לב העניין, אם כי אינו קשור ל ajax במאומה. הוא מעין handle-עתידי.
בעת קריאה ל ()deferred.resolve - יופעלו הפונקציות (ניתן לרשום מספר לא מוגבל של פונקציות, לכל אחד מהאירועים) שנרשמו ל done. במקרה זה - כתיבה של done ו donedone ללוג.
בעת קריאה ל ()deferred.reject - יופעלו הפונקציות שנרשמו ל fail. במקרה זה כתיבת fail ללוג.

ההתנהגות העצלה (deferred) נובעת, כפי שאתם בוודאי מבינים, מעצם רישום והפעלת פונקציות בג'אווהסקריפט. האובייקט Deferred הוא פשוט למדי ואינו כולל התנהגויות אסינכרוניות מיוחדות.

ה Promise הוא אובייקט (יחידון = singleton) שחוזר מקריאה ל ()deferred.promise וכל מטרתו היא לאפשר גישה מוגבלת: לאפשר לרשום פונקציות ל done, fail ו always - אבל לא לבצע triggering ל reject או resolve.

Read/Write Pattern - שליטה ב"הרשאות" ע"י הפרדת הפעולות ל interfaces שונים. אפשר להחליף את user ב promise ואת userMaint ב Deferred על מנת לראות את תבנית העיצוב בהקשר לדיון שלנו.

הערה: ל reject או resolve ניתן לקרוא פעם אחת בלבד בחיי אובייקט ה Deferred. מאותו הרגע, כל פונקציית callback שתנסה להירשם - תופעל במקום.

כעת, לאחר שהבנו את ההתנהגות של Promise, בואו נראה אלו בעיות מבנה זה יכול לפתור לנו.


Concurrent Pattern: Monitor
השימוש ב Deferred יכול לסייע לנו לבנות מבנה של concurrent programming בשם בקר (monitor). בקר הוא כלי לטיפול באסינכרוניות, הגבוה ברמת ההפשטה שלו מ mutex או semaphore, אך נמוך מ "synchronized" של ג'אווה / #C. אנו עשויים למצוא אותו דיי שימושי בשפת ג'אווהסקריפט / שימושי ב ajax בהם אסינכרוניות היא נפוצה [ב].

Monitor - מחכה שמספר פעולות אסינכרוניות יגיעו למצב מסוים, ואז יוזם פעולה. סוג של "יישור קו".

נאמר שאני מחכה בג'אוובסקריפט ל2 פעולות שיסתיימו: טעינה של נתונים מהשרת ואנימציית מעבר. רק ש2 אלו יסתיימו אני רוצה להציג dialog עם שאלה למשתמש.
הדרך הנאיבית לעשות זאת היא ש callback א' ישנה ערך גלובאלי כלשהו, ו callback ב' ימתין עד שהערך הגלובאלי השתנה. כאשר callback ב' מצא את הערך לו הוא ציפה - אני יודע ש2 הפעולות הסתיימו.
הבעיה?
הקוד קשה לקריאה: יהיה צורך לעקוב אחרי הלוגיקה של ה callbacks להבין מה הם עושים.
קרוב לוודאי שייוצר קוד מסורבל ומאוד לא נוח לתחזוקה.
הקוד לא יעיל מבחינת ביצועים.

הרבה יותר אלנגנטי, יעיל ונוח יהיה פשוט מאוד לכתוב:

var promiseA = $.get(...);
var deferredAnimation = $.Deferred(); // call  deferredAnimation.resolve() when it is done
var promiseB = deferredAnimation.promise();


$.when(promiseA, promiseB).
done(function(promiseAargs, promiseBargs) {
   ... // what happens when both are done 
});

תענוג!


מודולריות
השימוש העיקרי, והנפוץ יותר ל Promises הוא עבור callbacks פשוטים.
כפי שציינו קודם לכן, הקוד

$.get('http://server.com/myurl', {
  success: onSuccess, // a callback function to be triggered on success
  failure: onFailure, // a callback function to be triggered on failure
  always: onAlways // a callback function that is triggered on either failure of success. Like "finally".
});


נראה קריא למדי. הבעייה היא שזהו קוד שפשוט ונכון ל tutorials או קוד JavaScript קטן. כשמדובר בקוד JavaScript גדול קרוב לוודאי שנרצה לחלק את הקוד למודולים - כל אחד עם אחריויות משלו, והכרות מצומצמת של העולם - שתשמור אותו פשוט.

במערכות שכאלו, מה שסביר שיקרה הוא אחד מהבאים:
  • ה onSuccess callback יפנה לאזורים שונים במערכת ויבצע שינויים. למשל: העלמת שעון חול, הפיכת כפתור ל enabled, הוספת פריט לרשימה. קרוב לוודאי שפעולות אלו ישברו את ההכמסה של המודולים במערכת.
  • אם ישנה מודעות מספקת להכמסה, קרוב לוודאי שכל אובייקט יכלול פונקציית callback שיודעת להגיב לאירוע ולשנות את הערכים המקומיים למודול. אבל... איך מעבירים את ה callback למקום בה נעשית הצורה האסינכרונית? לעיתים זה יהיה פשוט כי הגיוני שתהיה תלות בין המודולים - ולעיתים קרובות נאלץ להעביר את ה callback בין אובייקטים רבים ולהוסיף אולי תלויות על מנת לבצע את הקישור. מי שראה קוד שמעביר מספר callbacks בין אובייקטים, על מנת לטפל באירועים שונים או פשוט callbacks ממקורות שונים, יודע עד כמה הקוד עלול להיות מסורבל ו"ללכלך" את המערכת. התועלת בהכמסה עלולה לפחות - אם המחיר הוא קוד סבוך כל כך! 
פתרון שבמקרים רבים יהיה אלגנטי למדי הוא שימוש ב promise בעת יצירת הקריאה האסינכרונית ותעבירו את ה promise לאובייקטים אחרים. אובייקטים אלו יוכלו להירשם לאירועים שמעניינים אותם, אבל מעבר לזה - להעביר את ה promise הלאה לאובייקטים אחרים על שמודול המקור לא מכיר. מה שנקרא "הכמסה". - כך שאובייקטים אחרים שהם מכירים יירשמו עליו.

יש פה ייתרון במספר האובייקטים המועברים. אם 2 אובייקטים שונים היו רוצים לדעת על הצלחה או כישלון של אירוע שיצרתם - הייתם צריכים להעביר 4 callbacks. במקום זה אתם יכולים להעביר promise אחד בלבד.


סיכום 
Promise הוא לא Silver Bullet, אבל במקרים רבים הוא יכול להיות כלי רב-עצמה שיתיר סיבוכיות רבה מהמערכת. היכולת לנתק את השליטה (קריאות resolve ו reject של Deferred) מצד אחד ואת התגובה לסיום הפעולה (done, fail ו always של ה promise) מצד שני מאפשרות לשמור על מודולריות גבוהה של המערכת במחיר נמוך.

אם אתם מוצאים את תבנית העיצוב של Deferred ו Promise שימושית, יש עוד פונקציות שניתן לחקור:
Deferred ו Promise יכולים לתקשר בניהם גם אודות progress (שלא כיסיתי בפוסט). לפעולת when יש פעולה "אחות" בשם then. חשובה אולי מכולן היא פעולת ה pipe שמתירה לשרשר הצלחות / כישלונות של promise וכך לחסוך קוד.


שיהיה בהצלחה!


---

[א] בגרסה 1.6 שונו שמות הפונקציות - אני משתמש בשמות החדשים. בגרסה 1.8 השמות הישנים (complete, success ו error) יוכרזו כמיושנים (deprecated) ולכן אני נמנע משימוש בהם.

[ב] בג'אווהקריפט בדפדפן יש כמובן thread יחיד ואין מקביליות חישוב. מצד שני יש הרבה פעולות IO אסינכרוניות שקוראות במקביל ויש אתגר תכנותי לשלוט בהן.


2012-07-14

מבוא מואץ לjQuery עבור מפתחי #C ו Java מנוסים

jQuery היא כל כך נפוצה בקרב מפתחי ווב, שניתן להתייחס אליה כחלק משפת JavaScript לדפדפן. קחו את jQuery מהעולם - ותמצאו מליון נשמות אבודות, שלא יודעות כיצד להמשיך ולכתוב אפליקציות ווב.

הבהרה: jQuery היא ספרייה ל JavaScript - לא הרחבה לשפה. היא פשוט מסייעת במידה כ"כ רבה עד שהפכה אצל מפתחים רבים לחלק בלתי נפרד מכתיבת קוד ב JavaScript. כאשר דפדפן אינו מעורב (לדוגמה node.js) - אין לה שום משמעות.

מה יש בה ב jQuery שהיא כ"כ מצליחה, ורבים כ"כ תלויים בה?
בפוסט זה אנסה לענות על השאלה.


שייך לסדרה מבוא מואץ ל JavaScript ו jQuery


לא מזמן שאלה אותי מישהי כיצד אני בוחר את רמת העומק / הפרטים של הפוסטים? מדוע הם יחסית high level ולא בפרטים? לא ידעתי בעצמי מה לענות.
"כי זו הרמה הקריטית יותר להצלחת הפיתוח" - עניתי, אבל לא שכנעתי את עצמי.
"אולי בגלל שאני ארכיטקט וזו רמת הפרטים שאני רגיל לה?" - ניסיתי שוב. לא ממש ידעתי.
ישנתי על זה לילה. אני חושב ששתי הסיבות הן:

  • להגיע לקהל יעד רחב
  • לכסות נישות שלא מכוסות היטב - כלומר Value Proposition ייחודי.

הקדמה
על jQuery יש טונות של חומרים. רוצים לדעת מה ההבדל בין live ל bind? עשרות מקורות טובים ישמחו להסביר. עם מעט חיפוש, גוגל יפנה אתכם לתשובה בודדת ב StackOverflow שעונה בדיוק, אבל בדיוק, על המקרה שאתם מתמודדים איתו. אבל יש משהו שנראה לי ייחודי ושקשה למצוא - מבט גבוה קצת מהפרטים, מפוכח ובעברית - על מה שקורה שם.
לפני כתיבת פוסט זה חיפשתי בגוגל "jQuery Crash Course" או "jQuery introduction". יש הרבה - אבל הם מספקים hands-on בכדי להתחיל להשתמש ב jQuery. הם לא מספקים הקדמה נאותה שתכין אתכם ללמידת jQuery או בכלל תעזור לכם להבין אם זה מה שאתם מחפשים. כשאני התחלתי ללמוד jQuery (לא כ"כ מזמן) - רציתי למצוא מישהו שיספר לי "מה העוקץ ב jQuery" - אך לא מצאתי. הנה זה לפניכם.
עלייתה של jQuery
תחילתה של jQuery היא בימי הביניים (של הדפדפנים - כמובן), ימים אפלים שהאנושות מנסה לשכוח.
בעוד JavaScript הייתה סטנדרטית (נניח...), ה APIs של הדפדפן לייצוג דף הHTML, מה שנקרא (Document Object Model (DOM, היה שונה למדי בין דפדפן לדפדפן. אמנם היו פונקציות עם שמות זהים (כמו getElementsByTagName) - אבל ההתנהגויות היו שונות. לעתים הן החזירו מבנים שונים, לפעמים הם קראו לאירועים (events) בסדר שונה. ובד"כ הן עשו את זה לאט ובצורה לא יעילה, תחת ההנחה ששינויים דינמיים ב DOM הם מעטים למדי. בקיצור: כל מה שלא הייתם רוצים מ API.
הכתיבה של קוד ווב Cross-Browser הייתה סיוט, ואכן רק אנשים מעטים הסכימו לעסוק במלאכה הבזויה[א]. ספריה שתספק API אחיד, אמין ומהיר עתידה להפוך לדבר שהמפתחים יהיו תלויים בו ולא יוכלו עוד בלעדיו.
כעשור מאוחר יותר, הדפדפנים מהירים יותר ואחידים יותר במבנה ה DOM APIs שלהם.
"מדוע מפתחים עדיין 'תלויים' ב jQuery?" - אפשר לשאול. ובכן, לשימוש ב jQuery יש הרבה תיעוד ודוגמאות - הרבה יותר מאשר שימוש ישיר ב DOM. בנוסף, בעוד ה API של ה DOM התפתח בקצב איטי ונשאר דומה למדי לתכנון בן 13+ שנים, jQuery יכלה להרשות לעצמה שינויים יותר דרמטיים שמשקפים יותר טוב את צורכי התקופה.

אז מה jQuery מספקת?
אמירה מקובלת היא ש "jQuery היא רק ספריה ל Selection" - אבל זה לא מדויק. jQuery מכסה מספר נושאים:

  • ביצוע שינויים ב DOM - קריאה וכתיבה.
  • מודל פשוט ואחיד יותר של אירועים (DOM events).
  • שיפורי ביצועים עבור טיפול בהרבה אירועים.
  • אנימציות - שיכולות להיות מופעלות על כל אלמנט ב DOM כמו Image, או Div שמאגד אלמנטים רבים.
  • הפשטה של XMLHttpRequest - מה שקרוי Ajax.
  • Utilities שונים לשימוש בג'אווהסקריפט, כגון each.$ או proxy.$
כפי שניתן לראות jQuery הוא דיי רוחבית. חוץ מהאנימציות שהן קצת "אקסטרה" - ספריה זו מספקת עטיפה ל DOM שמאפשרת לנו לעבוד איתו ברמת הפשטה קצת יותר גבוהה.

אלטרנטיבות
Prototype ו MooTools הן ספריות בעלות יכולות מקבילות, פחות או יותר. jQuery נצחה אותן בזכות קהילה, תיעוד טוב יותר או אולי אמינות גבוהה יותר.
Dojo, YUI או ExtJS/Sencha הן ספריות שמספקות רמת הפשטה גבוהה בהרבה ובעצם מנתקות אתכם מה DOM. הן נותנות למפתח לעבוד ברמה קרובה הרבה יותר ל Windows Forms או AWT ובעצם מייצרות מודל חדש אלטרנטיבי ל DOM שהמפתח עובד מולו.

יש המון כוח ויופי בכך ש jQuery לא מתארת מודל חדש, אלא רק מודל משופר של ה DOM. המפתח נותר עם קשר והבנה טובה בהרבה למה שקורה בפועל בתוך הדפדפן, ו jQuery יכולה להתחבר בקלות להמון ספריות שנכתבו בחשיבה על ה DOM. מי שרוצה ליצור ספרייה מעל YUI צריך לעבוד ע"פ המודל של YUI שעשוי בהחלט לא להתאים ל Dojo או ל ExtJS.



טעימה מיכולותיה של jQuery
לא אנסה להרשים אתכם בתצוגות-תכלית מגניבות. ה Adoption של jQuery הוא כבר מעבר לזה. אנסה לתת, בקצרה, טעימה מהיכולות העיקריות והסגנון של jQuery.

DOM Manipulation
בדומה לSQL בה יש משפטי SELECT...FROM...WHERE עם פורמט ידוע, גם ב jQuery יש דרך פעולה שחוזרת על עצמה. משפטי jQuery הם בעלי המבנה הבא:

$('selection').<execute>();


בחר שורה של אלמנטים - ובצע עליהם משהו: שינוי של HTML, CSS, רישום לאירועים ועוד.
חלק גדול מהיופי של jQuery היא הדרך בה היא משתלבת בטבעיות בנוף של HTML, JavaScript ו CSS. שפת CSS עושה פעולה דומה: בוחרת אלמנטים ב DOM (כלומר ב HTML) ומחילה (כלומר apply) עליהם עיצוב.
jQuery משתמשת בתחביר של javaScript לתאר את אותה התבנית. הנה דוגמה:

$('.banner').css('background-color', 'red');

שהיא המקבילה לכתיבת ה CSS הבא:

.banner {
  background-color : red;
}

מפתח שחדש ל jQuery אך בקיא ב CSS יוכל ללא קושי להגדיר שאילתות דיי מורכבות.
jQuery לא אמורה להיות תחליף ל CSS - לצורך זה היא תהיה משמעותית פחות יעילה, אבל היא מאפשרת באותה דרך חשיבה לבצע שינויים מרחיקי לכת בעזרת שורות בודדות של קוד.
התחביר של jQuery, בדומה ל javaScript, תומך בשרשור (chaining). פעולת ה Select מחזירה רשימה (באורך 0, 1 או יותר) של אלמנטים ב DOM. כל אחת מפעולות ה execute מחזירה את אותה הרשימה של אובייקטים עליה נקראה, כך שיהיה ניתן לשרשר עליה עוד ועוד פעולות:

$('div > p').show().css('color', 'blue').removeClass('selection');


קריאה זו תבחר את אלמנטי ה p (פסקה ב HTML) שנמצאים ישירות בתוך div, תציג אותם, תחיל על הטקסט צבע כחול ותסיר class בשם selection - אם קיים.
אם ננסה לתאר בצורה יותר כללית את תבנית כתיבת הביטויים ב jQuery - אפשר לתאר אותם כך:

$('selection').<execute>().<execute>().<filter>().execute();


פעולת הפילטר היא פעולה שמצמצמת את רשימת האובייקטים. "צמצום" יכול להיות גם פעולת בחירה במקרה זה, כאשר find בוחרת את אלמנטי ה strong הבנים לאלמנטי ה div שבחרנו:

$('div').css('border', '1px solid blue').fadeTo('slow', 0.5).find('strong').css('color', 'red');
​
הנה דוגמת ההרצה של קוד זה. אין מניעה שיהיו יותר אלמנטים של strong מאלמנטים div-אבות כמובן, כך שהשם "צמצום" (filter) הוא שם בהחלט לא מדויק. וריאציה אחרת של צמצום נקראת "טיול" או traversal. בעזרת פקודות כגון ()parent או ()siblings אפשר "לטייל" על ה DOM מהנקודה בה אתם נמצאים.
יש מספר רב של פעולות execute, traversal ו filter אפשריות - אני בטוח שגוגל יוכל לעזור לכם למצוא מידע רב על כולן.

טיפול באירועים (events)
jQuery מספקת רמת הפשטה נוחה יותר לאירועים ב DOM. לדוגמה, עבור hover סביר שמפתח יבחר להירשם לאירועים של ה DOM בשם mouseOver ו mouseOut, אבל היכרות אינטימית תלמד שברוב הדפדפנים שימוש ב mouseEnter ו mouseLeave הוא עדיף. jQuery חוסכת לכם ללמוד פרטים כאלו ומספקת אירוע hover (שדורש 2 פונקציות: כניסה ויציאה) שידע לעשות את הדבר הנכון עבור כל דפדפן.
עוד צרה קשה היא רישום מופעים רבים של אירוע.
נאמר שיש לכם גלריה עם 100 תמונות על המסך, שבפעולת Hover אתם רוצים להדגיש את התמונה (אחת מ 100) שכרגע העכבר מצביע עליה. הדרך הנאיבית היא לרשום את אירוע ה hover והטיפול בו 100 פעם, פעם עבור כל תמונה בגלריה. מחיר הביצועים עלול להיות הרסני.
עדיף בהרבה לרשום את אירוע ה hover פעם אחת על כל הגלריה, לאתר את התמונה הרלוונטית לאירוע ואז להפעיל את קוד הטיפול באירוע בעזרת ההקשר הנכון.
שיפור הביצועים הוא משמעותי מאוד, אבל לדפדפנים שונים יש חוקים שונים כיצד לעשות זאת. jQuery מספקת הפשטה טובה לסיבוכיות זו ונותנת לכם לרשום אירועים על "קבוצה של אלמנטים" בקלות רבה.



כיצד jQuery עובדת? (בקצרה)
jQuery היא ספריית JavaScript לכל דבר. מוסיפים אותה ל HTML Header ואז ניתן להשתמש בה.
jQuery רושמת אובייקט גלובלי בשם $ (שם חוקי ב javaScript) שהוא משמש כמפתח לפעולות שונות של הספריה.
כאשר מבצעים Selection (כלומר "בחירה") - לא מקבלים רשימה של האובייקטים האמיתיים ב DOM, כי אם wrappers של jQuery שמספקים API בטוח, cross-browser, ופשוט יותר.
ל jQuery יש אלגוריתם יעיל לביצוע selection ב DOM. הוא נקרא Sizzle וניתן למצוא אותו כספריית javaScript עצמאית. ספרייה זו באמת "רק עושה selection". הנה כמה כללים איך להשתמש ב jQuery בצורה יעילה.
יש שמועות על כך ש jQuery מבצעת caching לאלמנטים ב DOM. שמעתי אותן לא פעם. לא נתקלתי מעולם בזכר להתנהגות שנראתה כמו caching עבור פעולות DOM. בעיקרון, גישה ישירה ל DOM אמורה להיות תמיד מהירה יותר משימוש ב jQuery.

Plug-ins
ניתן לכתוב plugins ל jQuery. בפועל plugin הוא פונקציה שנרשמת על ה namespace של jQuery (כלומר, סימן ה $) ויכולה להשתלב בתבנית ה Select-execute.
לדוגמה, אני יכול לכתוב פונקציה שהופכת אלמנטים להציג מימין לשמאל, ע"י שינוי כל פרטמר אפשרי לתמוך בהתנהגות זו. במקום לקבל רשימה של wrappers ולעבור עליהם בלולאה, יהיה הרבה יותר אלגנטי להשתמש בפונקציה שלי בצורה הבאה:
$('.text .localizable').toRTL();

יש כמה כללים (המנעות מהתנגשויות על הסימן $, אתחול, ...) שכדאי להקפיד עליהם בעת כתיבת jQuery Plugin - יש מדריכים רבים באינטרנט שישמחו לספר ולהדגים זאת.
סה"כ ראיתי כמה jQuery Plugins שלא הייתה להם הצדקה אמיתית להיכתב כ Plugin. אני מנחש שאם jQuery הייתה קוראת ל Plugins בשם פחות מרשים (כמו jQuery Chained Function) - היו נכתבים הרבה פחות Plugins של jQuery.

---
[א] הפוסט מופנה למפתחי Server בשפות מודרניות, שם ה APIs המקובלים טובים בהרבה.