JavaScript Callback Functions ใช้ตอนไหนอะ(อาจจะงงหน่อยนะแต่มัน Work สุดๆ)
JavaScript Callback Functions ในหัวข้อนี้ก็คงมีหลายๆ Web Site คงได้นำเสนอหลักการทำงานกันให้เข้าใจได้เป็นอย่างดีนะครับไม่ว่าจะเป็นภาษาไทยภาษาอังกฤษ ผมเองก็หาศึกษาจาก Web Site เช่นกันจะซึ่งสามารถเข้าใจได้ไม่อยาก แต่ปัญหาของตัวผมเอง คือแล้วเราจะเอาอันมันมาใช้ตอนไหนดีละนี่และคือปัญหา สำหรับ Post นี้ผมเลยอยากที่จะขอยกตัวอย่างที่ ง่ายๆ และสามารถใช้ได้จริงครับ ถ้าเพื่อนๆ อ่านบทความนี้แล้วก็พอที่มองเห็นภาพ ประโยชน์ของเจ้า Callback กันบ้างนะครับ(แต่สำหรับคนที่เข้าใจเป็นอย่างดีแล้ว ถ้าผมนำเสนอผิดพลาดประการใดแนะนำผมได้นะครับ)
เรามาลองดู Code แบบแรกกันก่อนนะครับเราจะได้รู้ถึงปัญหา ก่อนอื่นสมมุติว่าเรากำลังจะเขียน Ajax ดึงข้อมูล 2 ครั้ง ถ้าเราเขียนแบบง่ายเราอาจจะเขียน การเรียกใช้งานแบบตัวอย่างด้านล่าง เราอาจจะเขียน JavaScript Ajax ขึ้นมาสอง Function ดังรูปด้าน Code ด้านล่าง ครับ
$.ajax({ url: 'UrlA', type: "GET", data: "{}", contentType: false, cache: false, processData: false, async: true, beforeSend: function (jqXHR, settings) { //console.log(jqXHR.progress) }, success: function (msg) { //Data วาด Table 1 var $table1 = $('#table1'); var contents = response.d; var html = ''; for (var i = 0; i < contents.length; i++) { html += '<td>' + contents[i] + '</td>'; } // add the new row to the table var $newRow = $('<tr></tr>').append(html).appendTo($table1); } , error: function (jqXHR, textStatus, errorThrown) { //fix bug error not set false } , complete: function (jqXHR, textStatus) { } }); //.ajax
ส่วนที่สอง
//Get Data เพื่อวาด Function Table ที่ 2 $.ajax({ url: 'URlB', type: "GET", data: "{}", contentType: false, cache: false, processData: false, async: true, beforeSend: function (jqXHR, settings) { //console.log(jqXHR.progress) }, success: function (msg) { //Data วาด Table 2 var $table2 = $('#table2'); var contents = response.d; var html = ''; for (var i = 0; i < contents.length; i++) { html += '<td>' + Name[i] + '</td>'+ '<td>' + Age[i] + '</td>'; } // add the new row to the table var $newRow = $('<tr></tr>').append(html).appendTo($table2); } , error: function (jqXHR, textStatus, errorThrown) { //fix bug error not set false } , complete: function (jqXHR, textStatus) { } }); //.ajax
ซึ่งจาก Code ด้านบนเป็นการเรียกข้อมูลจาก UrlA และ UrlB ซึ่งมีการ Return Data ที่ต่างกันซึ่งแน่นอนว่าการ Return Data ที่แตกต่างกันยอมต้องมีการแสดงข้อมูลที่แตกต่างกันด้วยครับ Code ด้านบน 80% เหมือนกันเกือบหมดซึ่งแตกต่างกันเพียงในส่วนของ Function Success ที่ใช้ในการ Render Table เท่านั้น
หากต่อไปข้างหน้าเรามีการ Render Table ที่ 3 เราก็ต้อง Duplicate Code แบบด้านบนขึ้นมาอีกมากมาย และถ้าเราต้องการเพิ่มอะไรบางอย่างลงไปบางอย่างเช่น การเพิ่ม Effect loading ลงใน Function beforeSend เราก็ต้องมานั่งแก้ทั้งสาม Function ซึ่งมันไม่สนุกเลย ผมจึงได้เขียน Function กลางขึ้นมาลองรับ ผมได้เพิ่ม Function CallServices
function CallServices(url, async) { $.ajax({ type: "POST", dataType: "json", beforeSend: function (jqXHR, settings) { //ใส่ Effect loading }, url: url, data: '', contentType: "application/json; charset=utf-8", async: async, success: function (msg) { //??????????? //??????????? //??????????? } , error: function (jqXHR, textStatus, errorThrown) { //fix bug error not set false } , complete: function (jqXHR, textStatus) { } }); //.ajax }
CallServices Function ที่รับมี Parameter url async
url ของ Service ที่เราต้องการจะเรียก
async ทำเพื่อไว้ใช้สำหรับให้มันทำงานแบบ Asynchronous และ Synchronous (เป็นของแถมครับ)
ซึ่งปัญหามันอยู่ตรงที่รูปด้านล่างยังไงเพราะมันใช้ Function เดียวกันแต่วาด Table ต่างกันแล้ว จะทำยังไงดีหว่า
ผมก็เลยแก้โดยใช้การ Return ผลลัพธ์ และนำผลลัพธ์ไปทำการ วาด Table ใคร Table มันตาม Code ด้านล่างครับ
function CallServices(url, async) { $.ajax({ type: "POST", dataType: "json", beforeSend: function (jqXHR, settings) { //ใส่ Effect loading }, url: url, data: '', contentType: "application/json; charset=utf-8", async: async, success: function (msg) { return msg; } , error: function (jqXHR, textStatus, errorThrown) { //fix bug error not set false } , complete: function (jqXHR, textStatus) { } }); //.ajax
ส่วนที่แก้ไข
ซึ่งดูแล้วก็น่าจะ work ครับซึ่งมันก็ Work จริงๆ ถ้าเราใส่ async เป็น False นะครับ การใส่ async เป็น False นั้นหมายถึงระบุให้มันทำงานแบบ Synchronous ซึ่งมันจะรอทำคำสั่งจนเสร็จและ Return ผลลัพธ์ได้ แต่ถ้าหากว่าเราระบุ async เป็น True แล้วมันจะโดนข้ามไปโดยปริยายครับ (ปัญหาทั้งหมดอยู่ที่ประโยชน์นี้แหละครับ)
มันถึงเวลาแล้วที่เจ้า CallBack จะได้ออกโรงสะทีแล้วครับ ผมเลยแก้ Function ซะใหม่โดยการเพิ่ม CallBack Function ดัง Code ด้านล่าง
มันถึงเวลาแล้วที่เจ้า CallBack จะได้ออกโรงสะทีแล้วครับ ผมเลยแก้ Function ซะใหม่โดยการเพิ่ม CallBack Function ดัง Code ด้านล่าง
function CallServices(url, async,callBack) { $.ajax({ type: "POST", dataType: "json", beforeSend: function (jqXHR, settings) { //ใส่ Effect loading }, url: url, data: '', contentType: "application/json; charset=utf-8", async: async, success: function (msg) { return callBack(msg); } , error: function (jqXHR, textStatus, errorThrown) { //fix bug error not set false } , complete: function (jqXHR, textStatus) { } }); //.ajax
ส่วนที่แก้ไขโดยการเพิ่ม ตัวแปล callBack และ เพิ่มการ Return ค่ากลับ
callBack ตัวนี้จะเป็นเราจะใช้รับ function และ return ตัว function พร้อมผลลัพธ์กลับไปทำงานที่ Function แม่ที่เรียกมัน
Code ที่ผมแก้ขึ้นมาใหม่
<!DOCTYPE html> <html> <head> <title></title> <meta charset="utf-8" /> <script src="jquery-2.1.4.min.js"></script> <script> $(document).ready(function () { //Get Data เพื่อวาด Function Table ที่ 1 CallServices('urlA', false, function (msg) { //Data วาด Table 1 var $table1 = $('#table1'); var contents = msg.d; var html = ''; for (var i = 0; i < contents.length; i++) { html += '<td>' + contents[i] + '</td>'; } // add the new row to the table var $newRow = $('<tr></tr>').append(html).appendTo($table1); }); //Get Data เพื่อวาด Function Table ที่ 2 CallServices('urlB', false, function (msg) { //Data วาด Table 1 var $table2 = $('#table2'); var contents = msg.d; var html = ''; for (var i = 0; i < contents.length; i++) { html += '<td>' + Name[i] + '</td>' + '<td>' + Age[i] + '</td>'; } // add the new row to the table var $newRow = $('<tr></tr>').append(html).appendTo($table2); }); }); function CallServices(url, async, callBack) { $.ajax({ type: "POST", dataType: "json", beforeSend: function (jqXHR, settings) { //ใส่ Effect loading }, url: url, data: '', contentType: "application/json; charset=utf-8", async: async, success: function (msg) { return callBack(msg); } , error: function (jqXHR, textStatus, errorThrown) { //fix bug error not set false } , complete: function (jqXHR, textStatus) { } }); //.ajax } </script> </head> <body> </body> </html>
Code ที่แก้ด้านบนจะมีข้อดีที่แฝงมาสองอย่างนะครับ
- ลดความซ้ำซ้อนของ Code Code ของเราก็จะสั้นลง
- หากมีการ แก้ไขเพิ่มความารถของ การ Call Serive เราก็แก้เพียงที่เดียว
- ข้อนี้สำคัญมากถือเป็นหัวใจของ Post นี้เลยก็ว่าได้ครับนั้นก็คือมันรองรับการทำงานแบบ
Asynchronous And synchronous
ไปโดยปริยาย เพียงแค่ใส่ True และ False ผมขออธิบายสักนิด (แบบภาคปฎิบัติเลยนะครับ ไม่ทฤษฏี)
แบบ urlA เป็น true ,urlB เป็น true : urlA urlB ใครโหลข้อมูล Success ก่อนวาด Table ก่อน
CallServices('urlA', true, function (msg) { //Data วาด Table 1 }); //Get Data เพื่อวาด Function Table ที่ 2 CallServices('urlB', true, function (msg) { //Data วาด Table 2 });
แบบ urlA เป็น false ,urlB เป็น true : urlA จะวาด Table ก่อนพอวาดเสร็จ และเมื่อ urlB โหลด Success เมื่อไหรถึงค่อยวาดTable (ในระหว่างที่รอโหลดของ urlB มันก็จะคำสั่งอื่นๆ โดยไม่ต้องให้ Success เหมือนกับ Url ) เพราะ urlA เป็น False นั้นหมายถึง การเรียกข้อมูลแบบ synchronous คือให้รอจนสำเร็จก่อนแล้วถึงยอมทำคำสั่งต่อไป (เพื่อนก็คง งงใช่ไหมครับว่าแล้วทำไมไม่ใช้เป็น Asynchronous ให้หมดคือมันจะมีบางกรณีที่ เราอาจต้องการค่าใน Table1 บางค่าใช้ค้นหา Table2 ที่สอง เราเลยจำเป็นต้องรอครับ)
CallServices('urlA', false, function (msg) { //Data วาด Table 1 }); //Get Data เพื่อวาด Function Table ที่ 2 CallServices('urlB', true, function (msg) { //Data วาด Table 2 });
แบบ urlA เป็น false ,urlB เป็น false : urlA จะถูกวาดก่อนแล้วจากนั้นก็จะทำ urlB ตามลำดับซึ่ง
CallServices('urlA', false, function (msg) { //Data วาด Table 1 }); //Get Data เพื่อวาด Function Table ที่ 2 CallServices('urlB',false, function (msg) { //Data วาด Table 2 });
หมายเหตุ ค่า Default ของ async ของ Ajax จะเป็น True นะครับ
async: async,
ที่มา :http://www.javascriptthai.com/?p=2189