มาใช้ EventEmitter กันดีกว่า by

31
Jan
1

EventEmitter คือ class ที่เอาไว้สร้างเหตุการณ์ต่างๆ สำหรับ Node.JS ถ้าเปรียบเทียบกับงานที่ทุกคนคงรู้จักกันก็เช่น event onclick เมื่อมีการคลิกให้ทำการเรียก function ที่กำหนดให้อัตโนมัติ ในบางภาษาจะเรียก AddEventListener นั่นเอง บางคนอาจจะคิดว่าทำต้องทำต้องเป็น event ด้วยในเมื่อเรียก function ตรงๆ ก็ได้ คำตอบคือการทำงานของ class EventEmitter จะเป็นการประกาศดักรอ event เมื่อ event เกิดขึ้นจึงค่อยทำงาน ซึ่งรูปแบบการทำงานจะเป็นลักษณะ passive รอถูกเรียก และสามารถประกาศรอรับ event กี่ที่ก็ได้ ทุกๆ ที่จะโดนเรียกทั้งหมด ทำให้สามารถทำงานได้สะดวกขึ้น

EventEmitter จะมีสอง method หลักๆ ที่ใช้งานคือ on และ emit ซึ่ง on เอาไว้ดักรอ event แล้วค่อยเรียก callback function ให้ทำงาน (AddEventListener)  ส่วน emit เอาไว้เป็นตัวสั่งการให้เกิด event ชื่อที่กำหนด และจะไปเรียก callback function ที่ประกาศรอไว้ในตอนแรกจนครบโดยอัตโนมัติ (ใน flash emit ก็คือ dispatchEvent นั่นเอง)

ตัวอย่าง code:
var EventEmitter = require('events').EventEmitter;
var util = require('util');
// create the class
var MyClass = function () { }
// inherit class
MyClass.prototype.__proto__ = EventEmitter.prototype;

var obj = new MyClass();
obj.on('startProgram', function(arg){
console.log('startProgram event run '+arg);
});

obj.on('startProgram', function(arg){
console.log('startProgram event run point 2 '+arg);
});

obj.emit('startProgram', '1');

ผลลัพธ์
startProgram event run 1
startProgram event run point 2 1

จะเห็นได้ว่าประกาศ on ไว้ 2 ที่ ก็จะโดนเรียกทั้ง 2 ที่ ซึ่งเวลาใช้งานจริงสามารถประกาศ on ที่ไฟล์อื่นก็ได้ (แต่ต้องส่ง instance ของ class ไปเพื่อเรียกใช้ด้วย) ทำให้เวลาทำงานจริงเราสามารถกำหนดโครงสร้างต่างๆ ได้ง่าย ตัวอย่างการใช้งาน EventEmitter อีกตัวที่เห็นได้ชัดก็คือ Socket.IO ที่ใช้ติดต่อส่งข้อมูลผ่าน network ไปยัง client นั่นเอง หรือแม้แต่ express ก็ใช้ EventEmitter นี่เช่นกัน จะเห็นได้ว่า EventEmitter เหมาะสำหรับงานทางด้าน network เป็นที่สุด เอาไว้สร้าง code ส่วนที่เป็น asynchronous ได้โดยง่าย

ใช้ Node.js วนลูป Callback แบบเรียงลำดับด้วย “async” Library by

24
Apr
0

ในบทความนี้จะพูดถึงการใช้งาน Node.js ในการวนลูป Callback ของการทำงานกับ Array ตามลำดับแบบ Synchronous ซี่งต่อจากนี้ไปจะขออธิบายปัญหาต่างๆ เป็นสถานการณ์ตัวอย่างครับ

สมมุติมี Array ชื่อ activities เก็บข้อมูล Object ดังนี้

var activities = [
{ title: "Raising my hand", time: 1000 },
{ title: "Crying in the rain", time: 5000 },
{ title: "Spinning my head", time: 2000 },
];

สิ่งที่จะทำคือต้องการให้ทำกิจกรรมต่างๆ ตาม [title] ในช่วงเวลา [time] milliseconds ให้ครบทั้ง Array ซึ่งคุณสามารถเขียน Loop เพื่อวนทำกิจกรรมง่ายๆ ได้ดังนี้

for(var i = 0; i < activities.length; i++) {
(function(){
var title = activities[i].title;
var time = activities[i].time;
console.log("+ " + title + " for " + time/1000 + " second(s)");
setTimeout(function(){
console.log("- " + title + " completed!");
}, time);
})();
}

จากโค้ดก็ไม่มีอะไรมาก เป็นเพียงการวนลูป setTimeOut ทำกิจกรรมตามเวลาของแต่ละกิจกรรม

ซึ่งเมื่อรันโค้ดดังกล่าว ผลลัพธ์ที่ได้คือ
+ Raising hand for 1 second(s)
+ Crying in the rain for 5 second(s)
+ Spinning head for 2 second(s)
- Raising my hand completed!
- Spinning my head completed!
- Crying in the rain completed!

สังเกตว่า การทำ Raising hand, Crying in the rain, Spinning head นั้นจะเริ่มทำพร้อมกันไปเลย เมื่อตัวไหนทำเสร็จก่อนก็จะเข้าสู่ Callback Function และรายงานผลว่าเสร็จแล้ว ซึ่งการทำแบบนี้เป็นวิธีการแบบ Asynchronous ตามแบบฉบับของ Node.js ที่ใช้ Javascript เป็นฐานอยู่แล้ว

แต่ในบางครั้ง เราต้องการผลลัพธ์ที่มีการกระทำตามลำดับทีละรายการ เช่น จากตัวอย่างด้านบนเราต้องการ Raising hand 1 วินาทีให้จบก่อน จากนั้นค่อย Crying in the rain 5 วินาที หลังจากนั้นค่อย Spinning Head อีก 2 วินาทีตามลำดับ จึงต้องมีการจัดลำดับ ให้ทำงานเป็น Synchronous ให้ได้ (ร้องไห้ไป หมุนหัวไป ยกมือไปพร้อมกันคงพิลึก)

ซึ่งถ้าเขียนตามปกติก็จะต้องเขียนโค้ดให้มีหลักการคร่าวๆ ประมาณดังนี้

console.log("+ Raising my hand for 1 second(s)");
setTimeout(function(){
console.log("- Raising my hand completed!");
console.log("+ Crying in the rain for 5 second(s)");
setTimeout(function(){
console.log("- Crying in the rain completed!");
console.log("+ Spinning my head for 2 second(s)");
setTimeout(function(){
console.log("- Spinning my head completed!");
}, 2000);
}, 5000);
}, 1000);

ผลลัพธ์ที่ได้

+ Raising my hand for 1 second(s)
- Raising my hand completed!
+ Crying in the rain for 5 second(s)
- Crying in the rain completed!
+ Spinning my head for 2 second(s)
- Spinning my head completed!

จะเห็นว่าผลลัพธ์ถูกต้องทุกประการ ทำตามลำดับอย่างดี แต่น่าเสียดายที่ตัวอย่างข้างต้นเป็นเพียงหลักการที่มีจำนวนชั้นของ Callback คงที่ ไม่สามารถนำไปใช้จริงกับ Array “ativities” ในตัวอย่างได้ เพราะเป็นไปไม่ได้เลยที่เราจะวนลูปเรียก Callback ในแต่ละสมาชิกของ Array ไปเรื่อยๆ จนกว่าจะครบทุกสมาชิกใน Array

วิธีการแก้ปัญหาอาจมีอยู่มากมาย แต่ในบทความนี้ขอนำเสนอคำสั่ง async.eachSeries() ซึ่งเป็นคำสั่งหนึ่งที่อยู่ใน Library ยอดนิยม “async” และมีรูปแบบการใช้งานที่ไม่ยุ่งยากมากนัก วิธีการใช้งาน ในขั้นตอนแรกจำเป็นต้องมี Library “async” เสียก่อน สามารถติดตั้งได้โดยพิมพ์คำสั่งด้านล่างใน Directory ที่ต้องการบนหน้าจอ Terminal หรือ Command Line

npm install async

และมีการใช้งานดังนี้

async.eachSeries(arr, iterator, callback);

โดย

  • array: Array ที่ต้องการท่องเข้าไป
  • iterator: ฟังก์ชันการทำงานที่ต้องการ
  • callback: สิ่งที่จะทำหลังจากการท่องไปยัง Array เสร็จสิ้นแล้ว

จากปัญหาที่กล่าวมา สามารถเขียนโค้ดได้ดังนี้

async.eachSeries(activities, function(activity, next)
{
var title = activity.title;
var time = activity.time;

console.log("+ " + title + " for " + time/1000 + " second(s)!");
setTimeout(function(){
console.log("- " + title + " completed!");
next();
}, time);
}, function(){
console.log("= All completed!");
});

จากตัวอย่างจะมีโค้ดที่คล้ายคลึงกับตัวอย่างแรกสุด แต่สิ่งที่ต้องมีในของ iterator มีดังนี้

  • พารามิเตอร์แรก (activity) เป็นพารามิเตอร์ที่เป็นตัวแทนของสมาชิกแต่ละตัวของ Array (ในที่นี้หมายถึงสมาชิกแต่ละตัวของ Array activitities)
  • พารามิเตอร์ที่สอง (next) เป็นพารามิเตอร์ที่เป็นฟังก์ชัน เพื่อนำไปเรียกใช้อ้างอิง Callback ของสมาชิกใน Array ตัวถัดไป
  • การเรียกใช้พารามิเตอร์ที่สอง (การใช้ next()) เป็นการบ่งบอกว่าจะไปเรียก Callback ของสมาชิกใน Array ตัวถัดไปแล้ว

เมื่อลองรันดู ผลลัพธ์ที่ได้คือ
+ Raising my hand for 1 second(s)!
- Raising my hand completed!
+ Crying in the rain for 5 second(s)!
- Crying in the rain completed!
+ Spinning my head for 2 second(s)!
- Spinning my head completed!
= All completed!

ซึ่งผลลัพธ์สามารถใช้งานร่วมกับ Array และตอบปัญหาของบทความนี้ได้แล้ว นั่นคือ Raising hand 1 วินาทีให้จบก่อน จากนั้นค่อย Crying in the rain 5 วินาที หลังจากนั้นค่อย Spinning Head อีก 2 วินาทีตามลำดับ

สามารถเข้าไปดูรายละเอียดการใช้งานและลูกเล่นอื่นๆ เพิ่มเติมได้ที่ https://github.com/caolan/async


Javascript “this”, “self” object by

29
Dec
0

เราคงจะคุ้นเคยว่าในภาษา OOP ทั่วๆ ไปอย่าง C#, Java นั้นจะมีการใช้งาน this เพื่ออ้างอิงถึงตัว obj ของ class นั้นๆ แต่ว่า this ใน javascript นั้นจะแตกต่างกันออกไป เราลองมาดูตัวอย่าง


var obj = {
items: ["a", "b", "c"],
process: function() {
this.items.forEach(function(item) {
this.print(item);
});
},
print: function(item) {
console.log('*' + item + '*');
}
};
obj.process();

ตัวอย่างนี้เราประกาศตัวแปรชื่อ obj มี properties ชื่อ items และมี function ชื่อ process กับ print เราสั่งให้ทำงานด้วย obj.process() ซึ่งจะเห็นว่ามีการสั่ง this.items.forEach ณ บรรทัดนี้โค้ดจะยังทำงานได้ดังที่เราคาดหวังอยู่ แต่เมื่อเข้ามาอยู่ใน forEach แล้วบรรทัดที่สั่ง this.print(item); ก็ควรจะทำงานได้เหมือน this.items ใช่ไหมครับ แต่เดี๋ยวก่อน! ลอง copy ไปรันใน Google Chrome Developer Tools หรือ Firebug ไหงไม่มีผลลัพธ์ออกมาเลยล่ะ! ลองมาดูที่บรรทัดนี้อีกครั้ง


this.items.forEach(function(item) {
this.print(item);
});

this.items อ้างถึง items จาก function ชื่อ process ได้ แต่ this.print ทำไมสั่งไม่ได้ล่ะ? เป็นเพราะเมื่อมีการประกาศ function(item) {} ซึ่งเป็น function anonymous (ไม่มีชื่อ) ขึ้นมาจะพบว่ามีการสร้าง block ขอบเขตให้ตัวแปร block ใหม่ การประกาศตัวแปรใดๆ ในนี้จะไม่สามารถถูกเรียกจากนอก scope function นี้ได้ใช่ไหมครับ เช่น


this.items.forEach(function(item) {
var a =5;
});
console.log(a);

แน่นอน เราไม่สามารถสั่งการแบบนี้ได้ a จะได้เป็น undefined เช่นเดียวกันกับตัวแปร this ซึ่งตัว javascript จะถือว่าเป็นตัวแปรภายใน scope anonymous function โดยอัตโนมัติ เราไม่ได้เป็นคนประกาศตัวแปรชื่อ this การที่เราสั่ง this.print(item) this นั้นเป็นตัวแปรภายใน scope ที่เราสร้างขึ้นเอง จะไม่สามารถอ้างอิงถึง function print ได้จริงๆ เพราะอยู่คนละ scope กัน ดังนั้น ทีนี้มาดูวิธีแก้ปัญหากันครับ


var self = this;
this.items.forEach(function(item) {
self.print(item);
});

เราจะสร้างตัวแปรชื่อ self มารับค่า this เอาไว้ก่อนเข้าส่วนของ forEach ซึ่งภาษา Javascript นี้สามารถอ้างอิงถึงตัวแปรที่อยู่ภายนอก scope ได้ (ตรงกันข้าม ไม่สามารถอ้างถึงตัวแปรที่อยู่ภายใน scope ที่ลึกกว่าได้ดังที่แสดงให้ดูไปแล้ว เนื่องจาก code ด้านในยังไม่ถูก execute จริงๆ) ทำให้มีตัวแปรที่จำค่า this ของก่อนเข้า forEach เอาไว้ พอมีการอ้างถึง self ซึ่งเก็บว่า this ของ scope ตัวนอกเอาไว้จึงสามารถทำงานได้เป็นปกติครับ เทคนิคนี้ถูกใช้อย่างแพร่หลายมากใน library javascript หลายๆ ตัว ดังนั้นถ้าเจอ self เมื่อไหร่ให้เดาได้เลยว่ามันคือ this ของ scope ตัวนอกครับ :)

Reference: http://book.mixu.net/ch4.html

การส่งค่าจากแฟลชให้แสดงที่ console ในเว็บเบราเซอร์ต่างๆ by

30
Sep
0

โดยปกติแล้วเราชาว Flash โปรแกรมเมอร์เวลาต้องการจะเช็คค่าที่ตำแหน่งต่างๆของโค้ดของเรา เราก็มักจะใช้ trace(“//string”); เพื่อเช็คค่าต่างๆขณะที่รันเทสแอปพลิเคชั่นของเรา แต่ในบางทีแล้วเราต้องการที่จะดักค่าที่เราต้องการทดสอบกับข้อมูลจริง ซึ่งต้องเป็นตัวที่ publish ไปรันบนแอปพลิเคชั่นจริงๆแล้วเราจึงไม่สามารถดู trace ที่เราเขียนขึ้นมาได้ เราจึงต้องมีการใช้วิธีต่างกันไป โดยวิธีที่จะนำมาเสนอในวันนี้จะเป็นดังนี้ครับ

เราจะทำการเรียกฟังก์ชั่น console.log ของ javascript ซึ่งจะแสดงค่าที่เราใส่ไว้ใน console ของ Developer Tools ที่มีใน Web Browser ในสมัยนี้ ซึ่งต่างๆกันไป

วิธีการเรียก console.log ก็จะมีหน้าตาดังนี้


ExternalInterface.call("console.log",[{
'test':"call me maybe"
}]);

จากการใช้ ฟังก์ชั่น ExternalInterface.call ซึ่งรับค่าสองตัว คือ ชื่อฟังก์ชั่น JS ที่จะเรียกและ ค่า Argument ที่จะส่งไปในฟังก์ชั่นนั้น ทำให้เราสามารถเรียกฟังก์ชั่น console.log ได้โดยใส่ค่าที่ต้องแสดงหรือตัวแปรที่ต้องการทราบค่า (นอกจากนั้นเรายังสามารถใส่ Object ทั้งก้อนเพื่อดูค่าด้านในได้เลยซึ่ง trace ทำไม่ได้)

ซึ่งจะทำให้เราเห็นค่าดังนี้

ตัวอย่างจาก Google Chrome (กด F12 แล้วเปิด Console ด้านล่าง)

ตัวอย่างจาก Google Chrome (กด F12 แล้วเปิด Console ด้านล่าง)

วิธี Invite Friend หรือส่ง Request ใน Facebook ด้วย Javascript SDK by

31
Oct
0

ก่อนจะอ่านต่อ แนะนำให้ไปอ่านการใช้งาน Facebook Javascript SDK เบื้องต้นที่บทความเก่าของผมอันนี้ก่อนครับ คือต้องสั่ง FB.init ก่อนจะใช้งานครับ จากนั้นเรามาดูรูปแบบคำสั่งกันเลยดีกว่าครับ (ถ้าใครใช้กับ app เก่าที่มีอยู่แล้ว ให้ปรับที่หน้า developer ของ app tab Advanced ให้ Requests 2.0 Efficient เป็น enable เอาไว้ด้วยครับ)

Request Dialog 2.0

Request Dialog 2.0

กู้เงิน | เศรษฐกิจพอเพียง | สินเชื่อบุคคล | สมัครบัตรกดเงินสด | สินเชื่อ | เงินกู้ด่วน | ยืมเงินทรูมูฟ | เงินด่วนนอกระบบ