כידוע, עולם ה-web הוא אסינכרוני. הרבה סוגים של רכיבים מרכיבים מערכת, וכל אחד מהם נטען בנפרד. לכל סוג יש דרך שונה להיטען, ודרך שונה להודיע שהוא נטען. ולפעמים, לא מספיק שהרכיב נטען בשלמותו, שכן הוא צריך להשפיע על רכיבים אחרים בעמוד, ולא תמיד יש לנו הדרך לדעת.
סוגי רכיבים נפוצים הם תמונה, קובץ css, קובץ javascript, פניית xmlhttp. לכל אחד מאלה יש אירוע בו אנו יודעים כי הוא נטען, אך עצם העובדה שהוא נטען לא אומרת שהוא התחיל להשפיע על העמוד שלנו.
לדוגמה:
- טעינה בזמן ריצה של קובץ css והשמתו על העמוד לא אומרת שמיידית הוא ישפיע על האלמנטים.
- קבלת html מתוך xmlhttp והשמתו על העמוד לא אומרת שמיידית כולו רונדר וניתן לגשת לרכיבים בו ללא בעיה
- טעינת קובץ javascript לעמוד לא אומרת שכל האובייקטים בו מוכנים לשימוש
לשם מצבי קצה אלו כתבתי פונקציה פשוטה בבסיסה, שממתינה עד אשר פעולה כלשהי בוצעה ורק אז מריצה קוד נוסף.
/// $waitUntil
/// waits until a certain function returns true and then executes a code. checks the function periodically
/// parameters
/// check - a function that should return false or true
/// onComplete - a function to execute when the check function returns true
/// delay - time in milliseconds, specifies the time period between each check. default value is 100
/// timeout - time in milliseconds, specifies how long to wait and check the check function before giving up
function $waitUntil(check,onComplete,delay,timeout) {
// if the check returns true, execute onComplete immediately
if (check()) {
onComplete();
return;
}
if (!delay) delay=100;
var timeoutPointer;
var intervalPointer=setInterval(function () {
if (!check()) return; // if check didn't return true, means we need another check in the next interval
// if the check returned true, means we're done here. clear the interval and the timeout and execute onComplete
clearInterval(intervalPointer);
if (timeoutPointer) clearTimeout(timeoutPointer);
onComplete();
},delay);
// if after timeout milliseconds function doesn't return true, abort
if (timeout) timeoutPointer=setTimeout(function () {
clearInterval(intervalPointer);
},timeout);
}
POC:
var globalVariable=0;
setTimeout(function () { globalVariable=1; },2000);
$waitUntil(
function () {
console.log("checking globalVariable="+globalVariable);
return globalVariable==1;
},
function () {
alert("done!");
}
);
בדוגמה אנו יכולים לראות שיש משתנה בשם globalVariableשמאותחל ל-0, ולאחר 2 שניות ערכו הופך ל-1 ידנית. הפונקציה $waitUntil מקבלת שתי פונקציות. האחת תחזיר true/false לפי בדיקה שתבצע, והשניה תבצע קוד שירוץ רק אחרי שהראשונה החזירה true.
* הפונקציה console.log שייכת ל-firebug/webkit/ie8 ולא נתמכת ב-ie6/7.
דוגמאות לשימושים יותר נפוצים:
ajax("url.htm",function (source) {
element.innerHTML=source;
$waitUntil(
function () { return document.getElementById("some-id-in-source")!=null; },
function () { /* source is rendered and #some-id-in-source is available */ }
);
});
loadCss("file.css",function () {
$waitUntil(
function () { return element.offsetHeight>0; },
function () { /* css is applied on this element */ }
);
});
loadJs("file.js",function () {
$waitUntil(
function () { return typeof(SomeTypeInFileJs)!="undefined"; },
function () { /* SomeTypeInFileJs is ready to use */ }
);
});
הפונקציות loadCss, ajax ו-loadJs טוענות אסינכרונית קבצים ומודיעות כשהם נטענו. ניתן למצוא מימוש שלהן בכל ספריית JavaScript המכבדת את עצמה.
3 תגובות
כתיבת תגובה
נראה אחלה.
אבל למה לא להשתמש באירוע onComplete? בדוגמאות שנתת פה, ובדרך כלל בטעינה של דברים, אתה עושה בקשה לשרת, למה לא להשתמש בcallback הזה ?
מהסיבה ש-onComplete לא תמיד מבשר על סיום פארסינג/רינדור. לפעמים צריך להמתין מעט עד שזה יקרה (זה יכול להיות אפילו 1ms, העיקר שהפעולה תתבצע על thread אחר).
came from davidwalsh.name site. but oops, which language is this can' understand
כתיבת תגובה
תגיות מותרות לשימוש בתוכן
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre>