Làm một việc tại một thời điểm Không giống như đa số các ngôn ngữ lập trình khác, javascript đơn giản là đơn luồng. Điều này đồng nghĩa với việc tại một thời điểm nó chỉ xử lý duy nhất một việc. Bất cứ tác vụ nào đều phải thực hiện lần lượt, khi một tác vụ của bạn thực hiện quá lâu cũng tương ứng với việc trình duyệt sẽ chờ xử lý tác vụ đó xong mới thực thi các tác vụ tiếp.
Mỗi tab hold một single thread Môi khi bạn mở thêm một tab mới trên trình duyệt, trình duyệt sẽ sinh ra một javascript single thread. các thread giữa các tab độc lập với nhau về logic xử lý. # 2. Heap And Stack
Mỗi Single Thread javascript sẽ có một bộ nhớ heap và stack. Giống đại đa số các ngôn ngư lập trình khác, heap là nơi lưu trữ các dạng dữ liệu về object, còn stack là nơi lưu trữ dữ liệu trong quá trình thực thi code. Stack của javascript là một dạng LIFO data storage, nôm na có thể hiểu là nơi lưu trữ các hàm hay câu lệnh nào đang được thực thi. Các lệnh sẽ được push vào theo thứ tự vào sau cùng ra đầu tiền. NHững cái ô vàng vàng mà các bạn nhìn thấy trong hình vẽ được gọi là một stack frame. Nếu bất kì lời gọi nào tại frame hiện tại bị lỗi, javascript print stack trace ra console log của trình duyệt. function baz(){ throw new Error('Something went wrong.'); } function bar() { baz(); } function foo() { bar(); } foo();
3. Eventloop and callback queue
Eventloop và callback queue là 2 component khá thú vị của javascript.
Hãy hiểu đơn giản thế này, Bây giờ bạn có một tác vụ, đó là gửi một http-request để lấy thông tin từ một trang web nào đó chẳng hạn, và tác vụ này cần một thời gian dài cơ 1 phút để xử lý. Nếu như trình duyệt sử dụng cùng một thread xử lý javascript cho việc xử lý các tác vụ mang tính delay trên thì sẽ ảnh hưởng đến trải nghiệm người dùng vì họ phải đợi 1 phút để có thể tiếp tục sử dụng. Để tránh việc này, với những tác vụ mang tính delay, tức là đòi hỏi thời gian dài để xử lý, trình duyệt đã viết riêng các đoạn code xử lý đống ấy bằng một ngôn ngữ khác và cung cấp cho bạn api để gọi cái đống phức tạp ấy một cách rất sáng sủa. Ví dụ, setTimeout, setInterval, các tác vụ liên quan đến httpRequest v.v... Đồng thời trong javascript runtime sẽ sinh ra thêm 2 component là eventloop và callback queue.
Callback queue ở đây là một queue chứa các hàm callback- thứ mà được ném vào cùng với lời gọi các api phức tạp ở trên. Ví dụ:
setTimeout(function(){
console.log("this function is callback");
},3000);
Ở ví dụ trên cái funtion bên trong được gọi là callback, khi lời gọi hàm setTimeout được thì xong, thì hàm callback kia sẽ được đẩy vào callbackqueue.
Eventloop là thằng luôn luôn lắng nghe cái callback queue kia xem có thằng nào xuất hiện không thì bên nhấc nó ra thực thi lần lượt. Ở đây khi hàm callback được push vào callback queue thì thằng eventloop đang làm nhiệm vụ lắng nghe bống thấy một ông callback funtion được push vào, ngay lập tức, nó bê cái funtion callback đó ra stack để thực thi, và tiếp tục nhiệm vụ lắng nghe của mình.
Như vậy, về cơ bản, những component giúp javascript hoạt động m đã liệt kê ở trên
Vì Number() constructor (là khi bạn sử dụng với từ khoá new) sẽ tạo mới một Number Object với rất nhiều thứ kèm theo. Còn Number() function sẽ tạo ra một số thông thường (primitive).
const x = newNumber("6666");
console.log(x); // => Number {6666}const y = Number("6666");
console.log(y); // => 6666
Một số ví dụ khác:
const x = Number('66,66');
console.log(x); // => NaNconst y = Number('66.66');
console.log(y); // => 66.66const z = Number('66666');
console.log(z); // => 66666
Qua ví dụ trên, bạn thấy rằng: nếu String truyền vào không phải Number thì kết quả thu được là NaN; nếu tham số truyền vào không phải số nguyên thì kết quả không bị làm tròn.
Sử dụng parseInt() và parseFloat()
Phương thức parseInt()
Phương thức parseInt() là một giải pháp thường hay được sử dụng. Phương thức này sẽ parse String tuỳ theo hệ cơ số xác định. Vì vậy, mình đã thường xuyên sử dụng cách này để convert String sang Number trong JavaScript.
Ví dụ:
const x = parseInt('1000.12', 10);
console.log(x); // => 1000const y = parseInt('1000', 16);
console.log(y); // => 4096const z = parseInt('1000', 8);
console.log(z); // => 512const t = parseInt('1000', 2);
console.log(t); // => 8
Với giá trị của hệ cơ số hợp lệ là từ 2 đến 36. Trong trường hợp bạn không truyền giá trị của hệ cơ số vào thì JavaScript sẽ tự parse theo nguyên tắc:
String bắt đầu bằng "0x" hoặc "0X" => hệ cơ số 16 (hexadecimal)
String bắt đầu bằng "0" => hệ cơ số 8 (octal) hoặc 10 (decimal) tuỳ thuộc vào trình duyệt
String bắt đầu bằng các số khác thì => hệ cơ số 10 (decimal)
String bắt đầu không phải là số => NaN
Ví dụ:
const x = parseInt('1000.12');
console.log(x); // => 1000const y = parseInt('0x1000');
console.log(y); // => 4096const z = parseInt('01000');
console.log(z); // => 1000const t = parseInt('b1000');
console.log(t); // => NaN
Kết quả có vẻ hơi khó đoán nhỉ?
Theo mình, tốt nhất là luôn truyền vào giá trị của hệ cơ số muốn parse để luôn thu được giá trị như mong muốn.
Phương thức parseFloat()
Nếu như phương thức parseInt() luôn trả về kết quả là một số nguyên thì phương thức parseFloat() sẽ trả về kết quả là một số float.
Ví dụ:
const x = parseFloat('1000,12', 10);
console.log(x); // => 1000const y = parseFloat('1000.12', 10);
console.log(y); // => 1000.12const z = parseFloat('1000.120', 10);
console.log(z); // => 1000.12const t = parseFloat('1000', 10);
console.log(t); // => 1000
Sử dụng toán tử +
Ví dụ:
const x = +'1000,12';
console.log(x); // => NaNconst y = +'1000.12';
console.log(y); // => 1000.12const z = +'1000.120';
console.log(z); // => 1000.12const t = +'1000';
console.log(t); // => 1000
Sử dụng Math.floor()
Phương thức Math.floor() khá giống với phương thức parseInt() phía trên.
Ví dụ:
const x = Math.floor('1000.12');
console.log(x); // => 1000const y = Math.floor('0x1000');
console.log(y); // => 4096const z = Math.floor('01000');
console.log(z); // => 1000const t = Math.floor('b1000');
console.log(t); // => NaN
Sử dụng toán tử *
Ví dụ:
const x = '1000,12' * 1;
console.log(x); // => NaNconst y = '1000.12' * 1;
console.log(y); // => 1000.12const z = '1000.120' * 1;
console.log(z); // => 1000.12const t = '1000' * 1;
console.log(t); // => 1000
Sử dụng toán tử /
Ví dụ:
const x = '1000,12' / 1;
console.log(x); // => NaNconst y = '1000.12' / 1;
console.log(y); // => 1000.12const z = '1000.120' / 1;
console.log(z); // => 1000.12const t = '1000' / 1;
console.log(t); // => 1000
Sử dụng toán tử -
Ví dụ:
const x = '1000,12' - 0;
console.log(x); // => NaNconst y = '1000.12' - 0;
console.log(y); // => 1000.12const z = '1000.120' - 0;
console.log(z); // => 1000.12const t = '1000' - 0;
console.log(t); // => 1000
Sử dụng Bitwise not ~~
Ví dụ:
const x = ~~'1000,12';
console.log(x); // => 0const y = ~~'1000.12';
console.log(y); // => 1000const z = ~~'1000.120';
console.log(z); // => 1000const t = ~~'1000';
console.log(t); // => 1000
Sử dụng toán tử dịch >>>
Ví dụ:
const x = '1000,12' >>> 0;
console.log(x); // => 0const y = '1000.12' >>> 0;
console.log(y); // => 1000const z = '1000.120' >>> 0;
console.log(z); // => 1000const t = '1000' >>> 0;
console.log(t); // => 1000
Lời kết
Trên đây là một số cách để convert String sang Number trong JavaScript. Để so sánh tốc độ giữa các cách này, bạn có thể tham khảo và viết thêm testcase để so sánh tại Convert a string to a number using JavaScript.
Ngoài ra, bạn thường hay sử dụng cách nào để convert String sang Number trong JavaScript? Mình hy vọng được biết thêm nhiều cách khác nữa của bạn trong phần bình luận phía dưới!
Nếu bạn chưa biết thì Cloudinary là một dịch vụ lưu trữ, quản lý và phân phối media gần như miễn phí. Bạn có thể upload hình ảnh, video lên Cloudinary rồi phân phối chúng qua hệ thống CDN. Cloudinary dựa vào CDN của những ông lớn như Akamai, Fastly, và CloudFront, tự động chọn lấy nhà phân phối đang có hiệu suất tốt nhất để đảm bảo tài liệu được chuyển đến người sử dụng chỉ trong vòng vài nốt nhạc.
Ngoài chuyện upload, bạn còn có thể trực tiếp chỉnh sửa tài liệu (gọi là "transformation") chỉ bằng việc thay đổi tham số trên URL của tài liệu, chẳng hạn như chỉnh kích thước ảnh, đổi định dạng, crop hình, vân vân và mây mây. Cloudinary còn có những tính năng nâng cao khác mà bạn có thể tìm hiểu thêm ở đây.
Mình sử dụng Cloudinary cho Ehkoo từ những ngày đầu tiên. Cloudinary đặc biệt hào phóng khi cung cấp gói Free cho phép chứa 10GB media, 20GB bandwidth, 300k tập tin và 20k thao tác chuyển đổi hàng tháng. Theo ước lượng ban đầu của một trang không ai thèm vào thì gói này là đủ rồi, cho đến một ngày...
Khoảng 3 tuần trước, mình nhận được một email từ Cloudinary nhắc nhở rằng tài khoản đã sử dụng gần hết bandwidth trong tháng. Bình thường thì website sử dụng khoảng 80-90% bandwidth cho phép, nên chuyện này cũng không có gì lạ lắm. Nhưng vì đây là lần đầu tiên nhận được email cảnh báo nên cũng đáng để xem xét thử.
Thống kê cho thấy ngày hôm đó có 8.64k requests, ngốn 1.06GB bandwidth.
Suy nghĩ đầu tiên: Hmm, anh đẹp trai nào hotlink mấy tấm hình của iem rồi.
Nhưng "Thật bất ngờ - Trúc Nhân", thống kê khác cho thấy phần lớn requests lại đến từ chính ehkoo.com. Có nghĩa là website "vô tình" có thêm traffic, đẩy bandwidth hình ảnh lên cao.
Tuy nhiên cũng không quên chỉ mặt điểm danh anh Tét Văn Thót Chấm Vê Nờ đã tích cực lấy bài đồng thời tích cực hotlink nha.
Suy nghĩ tiếp theo: Có khi nào Cloudinary giả vờ tính sai để ép mình mua gói trả phí không?
Trong khoảng thời gian từ 1/10 đến 31/10/2018 thì Ehkoo có 12,637 lượt truy cập. Tính trung bình mỗi lần load trang khoảng 10 hình (ngoài trang chủ thì nhiều hình hơn), mỗi hình tầm 200KB, vị chi là khoảng 25,274,000KB ~ 25.274GB . Vậy là Cloudinary có lý khi gửi email cảnh báo.
Thành thật xin lỗi anh Cloudinary vì em đã nghi ngờ anh .
Thiệt may vì ngoài chuyện "la làng", Cloudinary còn tốt bụng gợi ý thêm vài chiêu để giảm bandwidth xuống.
25% of your bandwidth is being used to deliver PNG images. You can save considerable bandwidth by delivering non-transparent PNGs as JPGs. If you aren’t already doing so, consider using the ‘lossy’ flag to do this conversion automatically.
Consider using automatic WebP, JPEG-XR and JPEG image format selection for each different browser using 'f_auto' in delivery URLs.
Accessing original images without any transformation is responsible for 89% of your bandwidth usage. If possible, specify image dimensions to match the actual view size.
Ồ kê, đã có hướng dẫn, bắt đầu làm thôi.
Bắt đầu tối ưu hoá
Chuyển PNG thành JPG
Bước đầu tiên quá rõ ràng rồi, chuyển tất cả hình PNG thành JPG để giảm dung lượng file xuống. Thao tác này khá đơn giản vì Cloudinary cho phép bạn đổi định dạng hình ảnh chỉ bằng cách đổi đuôi file trên URL là xong.
Có một điểm lưu ý là tập tin JPG không hỗ trợ nền trong suốt (transparent background), nhưng vì web của Ehkoo nền trắng nên cũng không thành vấn đề. Bài học ở đây là nên thiết kế web nền trắng nhé.
Tự động chuyển qua WebP nếu trình duyệt hỗ trợ
WebP là một định dạng ảnh mới được phát triển bởi Google từ 2010. So với JPG thì WebP thường có dung lượng nhỏ hơn khoảng 30%, nhưng vẫn đảm bảo chất lượng tương đương. WebP hỗ trợ nền trong suốt như với PNG nhưng có thể nhẹ hơn đến 25%. WebP cũng hỗ trợ ảnh động như GIF nhưng có vẻ vẫn chưa phổ biến lắm.
Hiện tại các trình duyệt có thể đọc hiểu WebP bao gồm Chrome (duh), Opera và Edge. Firefox sẽ hỗ trợ WebP từ phiên bản 65, riêng Safari thì vẫn chưa thấy nói gì. Xem hỗ trợ WebP ở CanIUse.
Bằng cách thêm vào tham số f_auto, Cloudinary sẽ tự động trả về file hình ở định dạng WebP nếu trình duyệt của người dùng hỗ trợ. Trong trường hợp còn lại, hình JPG sẽ được trả về.
Thêm lý do nữa, là 63% lượng khách truy cập Ehkoo sử dụng Chrome cùng với 11% sử dụng Chrome Mobile, nên chỉ cần hiển thị WebP cho 3/4 tổng lượng truy cập cũng đã là một cải tiến lớn rồi.
Ngoài lề, liệu WebP có thống trị định dạng hình ảnh sau này?
Hên xui. Một trong những những hạn chế của WebP là không hỗ trợ tải ảnh theo kiểu tăng tiến (progressively). Nghĩa là trình duyệt vẫn phải download hết file ảnh trước khi hiển thị. Ở mức độ nào đó thì hạn chế này có thể ảnh hưởng đến trải nghiệm người dùng. MozJPEG, một định dạng ảnh được phát triển bởi Mozilla, có thể giải quyết hạn chế này, đồng thời vẫn đảm bảo những tính năng hay ho của WebP.
Nếu bạn quan tâm hơn về chủ đề tối ưu hoá hình ảnh, đừng bỏ qua bài thuyết trình dưới đây của Kornel Lesiński tại hội nghị performance.now() vừa diễn ra hồi đầu tháng 11. Kornel giải thích cách tập tin JPG được mã hoá, trình bày một kỹ thuật sử dụng HTTP2 để tiến hành tải ảnh một cách tăng tiến (ở cả server của bạn lẫn CDN), và một mẹo "kỳ cục" để sử dụng hình được nén bằng AV1 ngay hôm nay
Mách nhỏ Bạn nên nghía qua https://squoosh.app/, công cụ chuyển đổi ảnh trực tuyến vừa được Google giới thiệu tại hội nghị Chrome Dev Summit 2018 vừa qua. Ứng dụng này cho phép bạn chuyển đổi qua lại giữa các định dạng với nhau, hỗ trợ cả WebP và MozJPEG.
Nếu không sử dụng Cloudinary để tự động truyền tải WebP, bạn có thể dùng thẻ PICTURE để thực hiện fallback.
Trình duyệt sẽ tự động chọn lấy nguồn ảnh phù hợp, và trong trường hợp xấu nhất, sử dụng hình của thẻ IMG. Thẻ SOURCE còn hỗ trợ thuộc tính media, cho phép bạn quy định media queries khi hình ảnh này được hiển thị.
Hiện tại thì thẻ PICTURE đã có thể dùng được trên tất cả trình duyệt thường xuân (evergreen) trừ IE ra nhé :p
Thu nhỏ hình ảnh
Cái này thì nhờ vào tình hình thực tế của Ehkoo thôi. Website hiện tại đang có giao diện giống như bên dưới.
Vì container không bao giờ vượt quá 1280px và nội dung chính không vượt quá 960px, Ehkoo chỉ cần để chiều rộng của hình trong khoảng 1000px là tương đối hiệu quả rồi. Để tự động điều chỉnh kích thước ảnh, bạn thêm vào tham số c_scale,w_XXX với XXX là chiều rộng mong muốn. Cloudinary sẽ giữ nguyên tỉ lệ ảnh sau khi chỉnh sửa.
Đây là tình hình của Ehkoo trong 30 ngày qua. Sau khi áp dụng tất cả chiêu trò ở trên thì mọi thứ có vẻ khá khả quan. Lấy con số ra hù nhau một chút:
Ngày
Requests (1000)
Bandwidth (GB)
29/10
8.64
1.06
06/11
22.2 (257%)
1.25 (118%)
12/11
25.7 (297%)
1.71 (161%)
Số % là so sánh với ngày 29/10 - trước khi áp dụng tối ưu hóa
Trong những ngày đỉnh điểm, lượng request tăng lên 2.5 - 3 lần, trong khi bandwidth tiêu thụ chỉ tăng khoảng 1.2 - 1.6 lần. Hiện tại, website chỉ đang sử dụng khoảng 74% tổng lượng bandwidth cho phép.
Trong khi đó, số pageviews và sessions vẫn tiếp tục tăng.
Tạm kết
Tình hình đã tạm ổn nhưng vẫn còn nhiều chỗ cần cải tiến thêm. Chẳng hạn như hình ảnh ngoài trang chủ vẫn đang sử dụng hình với kích thước gốc, hay hình thu nhỏ ở phần Bài viết liên quan cũng vậy. Dù sao thì nếu website/ứng dụng của bạn cần chứa hình ảnh, hãy cân nhắc chuyển qua WebP và sử dụng Cloudinary nhé.
43 thủ thuật hay và hữu ích với Javascript (Phần 2)
Javascript là một trong những ngôn ngữ phổ biến nhất trong thế giới lập trình, ngôn ngữ không thể thiếu trong lập trình web thậm chí với JS chúng ta có thể code server hay cả mobile. Với Javascript chúng ta có thể tạo từ một alert đơn giản trên trình duyệt cho đến việc dùng nó điều khiển một con robot(sử dụng Nodebot & Nodruino).
Nếu các bạn đã từng gặp những hoàn cảnh trớ trêu khi code JS thì đừng nản chí, bởi vì nó là một mớ hỗn độn mà (facepalm).
Trong phạm vi bài viết này, Mình sẽ chia sẻ một bộ các thủ thuật về Javascript và các mẫu ví dụ mà ai trong chúng ta khi đụng đến Javascript đều nên biết và áp dụng một lần.
21. Sử dụng AND/OR cho biểu thức điều kiện
1
2
3
4
5
varfoo=10;
foo==10&&doSomething();// nếu foo == 10 thực hiện hàm Something();
foo==5||doSomething();// nếu (foo != 5) thì doSomething();
Logic OR cũng nên được sử dụng để đặt giá trị mặc định cho tham số truyền vào của hàm
1
2
3
4
5
functiondoSomething(arg1){
arg1=arg1||10;// arg1 sẽ nhận giá trị 10 nếu nó chưa được khai gán trước đó.
}
22. Sử dụng phương thức map() cho vòng lặp của một mảng
1
2
3
4
5
6
varsquares=[1,2,3,4].map(function(val){
returnval *val;
});
// squares <=> [1, 4, 9, 16]
23. Làm tròn số
1
2
3
4
varnum=2.443242342;
num=num.toFixed(4);// num nhận giá trị mới: "2.4432"
Lưu ý rằng hàm toFixed() trả về một chuỗi string, không phải là một số. Bạn cần parse nó nếu muốn nhận giá trị mới là một số.
24. Vấn đề dấu chấm động
1
2
3
4
5
0.1+0.2===0.3// is false
9007199254740992+1// tương đương 9007199254740992
9007199254740992+2// tương đương 9007199254740994
Tại sao lại 0.1 + 0.2 === 0.3 // => false? 0.1 + 0.2 bằng 0.30000000000000004. Những gì bạn cần biết là tất cả các bộ số trong Javascript là các số thực dấu chấm động được biểu diễn theo bộ nhị phân 64 bit, chuẩn IEEE 754. Bạn có thể tìm hiểu thêm ở link
Bạn có thể dùng toFixed() và toPrecision() để giải quyết vấn đề trên.
25. Kiểm tra thuộc tính của một đối tượng khi sử dụng vòng lặp for-in
Đoạn mã sau sẽ hữu ích khi bạn muốn tránh lặp qua các thuộc tính từ prototype của đối tượng.
1
2
3
4
5
6
7
for(varname inobject){
if(object.hasOwnProperty(name)){
// do something with name
}
}
26. Toán tử comma(dấu ,)
Trong Javascript, toán tử comma cũng tương tự trong C++, nó dùng gộp các phép toán lại với nhau, theo thứ tự phân cách bởi dấu ,
1
2
3
4
5
6
vara=0;
varb=(a++,a+99);
console.log(a);// 1
console.log(b);// 100
27. Lưu các biến cần tính toán hay cần truy vấn
Trong khi sử dụng Jquery selector, chúng ta nên tạo biến lưu các thành phần DOM.
1
2
3
4
5
6
varnavright=document.querySelector('#right');
varnavleft=document.querySelector('#left');
varnavup=document.querySelector('#up');
varnavdown=document.querySelector('#down');
28. Hãy xác định cụ thể tham số nào đó trước khi cho nó vào hàm isFinite()
Hãy xem ví dụ sau để xem các giá trị trả vể của hàm isFinite() nhé:
1
2
3
4
5
6
7
8
9
isFinite(0/0);// false
isFinite("foo");// false
isFinite("10");// true
isFinite(10);// true
isFinite(undefined);// false
isFinite();// false
isFinite(null);// true !!!
29. Không sử dụng chỉ số âm cho arrays
1
2
3
4
5
varnumbersArray=[1,2,3,4,5];
varfrom=numbersArray.indexOf("foo");// from = -1
numbersArray.splice(from,2);// [5]
Hãy chắc chắn rằng tham số truyền vào hàm splice() không phải là số âm.
30. Serialization và deserialization (với dữ liệu dạng JSON)
31. Tránh sử dụng eval() hay hàm tạo của Function nhiều
Việc dùng hàm tạo hay hàm eval() sẽ tiêu tốn nhiều tài nguyên bởi mỗi lần gọi nó là mỗi lần các công cụ biên dịch phải chuyển đổi mã nguồn thành mã thực thi.
1
2
3
4
varfunc1=newFunction(functionCode);
varfunc2=eval(functionCode);
32. Tránh sử dụng with()
Sử dụng with() sẽ chèn thêm biến toàn cục, vì thế nếu có một biến cùng tên có thể gây nhầm lẫn và bị ghi đè.
33. Không nên sử dụng for-in cho mảng
Thay vì sử dụng:
1
2
3
4
5
6
varsum=0;
for(variinarrayNumbers){
sum+=arrayNumbers[i];
}
Thì cách tốt hơn là:
1
2
3
4
5
6
varsum=0;
for(vari=0,len=arrayNumbers.length;i<len;i++){
sum+=arrayNumbers[i];
}
i và len sẽ được khởi tạo một lần bởi vì nó nằm trong câu lệnh đầu tiên của vòng lặp for
for (var i = 0; i < arrayNumbers.length; i++)
Tại sao? Bởi độ dài của arrayNumbers được tính toán lại mỗi khi vòng lặp lặp lại. Lưu ý: Việc tính toán lại độ dài trong mỗi lần lặp đã được cập nhật trong các Javascript engine mới nhất.
34. Truyền function vào setTimeout(), setInterval() thay vì truyền chuỗi string vào
Nếu bạn truyền một chuỗi string vào, chuỗi này được xác định với cách tương tự như hàm eval(), là cách chậm hơn. Thay vì dùng chuỗi:
1
2
3
4
setInterval('doSomethingPeriodically()',1000);
setTimeout('doSomethingAfterFiveSeconds()',5000);
Hãy viết trực tiếp vào
1
2
3
4
setInterval(doSomethingPeriodically,1000);
setTimeout(doSomethingAfterFiveSeconds,5000);
35. Sử dụng switch-case thay vì dùng if-else
Sử dụng switch-case sẽ nhanh hơn khi có nhiều hơn 2 trường hợp so sánh, và code dễ nhìn hơn. Và cũng nên tránh sử dụng nó nếu bạn có nhiều hơn 10 cases.
36. Sử dụng switch-case với dải số
Bạn có thể sử dụng switch-case với dải số.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
functiongetCategory(age){
varcategory="";
switch(true){
caseisNaN(age):
category="Sai gía trị rồi :)";
break;
case(age>=50):
category="Lớn tuổi";
break;
case(age<=20):
category="Thiếu niên";
break;
default:
category="Bất tử!";
break;
};
returncategory;
}
getCategory(5);// "Thiếu niên"
37. Tạo một đối tượng mà prototype của nó là một đối tượng
Chúng ta có thể tạo một đối tượng mà prototype của nó là những kiểu cung cấp như sau:
Hàm này có thể dùng trong trường hợp người dùng thêm code html vào trang web:
1
2
3
escapeHTML('<div class="abc"></div>')
Kết quả trả về sẽ là
1
2
3
"<div class="abc"></div>"
39. Tránh việc dùng try-catch trong vòng lặp
Try-catch tạo thêm một biến mới trong phạm vi hiện tại tại thời gian chạy, mỗi khi mệnh đề try-catch được thực thi, ngoại lệ đã bắt được gán cho một biến.
Thay vì sử dụng:
1
2
3
4
5
6
7
8
9
10
11
varobject=['foo','bar'],i;
for(i=0,len=object.length;i<len;i++){
try{
// code here
}
catch(e){
// handle exception
}
}
Hãy dùng:
1
2
3
4
5
6
7
8
9
10
11
varobject=['foo','bar'],i;
try{
for(i=0,len=object.length;i<len;i++){
// code here
}
}
catch(e){
// handle exception
}
40. Hãy đặt thời gian timeout cho việc chạyAjax(XMLHttpRequest)
Giả sử một ajax call tiêu tốn nhiều thời gian vì có vấn đề về mạng hay vấn đề nào đó. Khi đó bạn nên hủy bỏ gọi ajax bằng hàm setTimeout()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
varxhr=newXMLHttpRequest();
varurl=''
xhr.onreadystatechange=function(){
if(this.readyState==4){
clearTimeout(timeout);
// xử lý trả về
}
}
vartimeout=setTimeout(function(){
xhr.abort();// gọi hàm báo lỗi
},60*1000/* timeout after a minute */);
xhr.open('GET',url,true);
xhr.send();
Bạn nên tránh hoàn toàn các hàm ajax đồng bộ.
41. Xử lý trường hợp Websocket hết thời gian
Bình thường khi kết nối Websocket đã được xác nhận, server sẽ đặt một thời gian hết hạn kết nối cho kết nối đó trong khoảng 30s nếu nó không hoạt động. Firewall của server cũng sẽ đặt thời gian timeout sau một quãng thời gian không hoạt động.
Để thay đổi thời gian timeout của server, trong trường hợp bạn không có tương tác gì, sau một thời gian hãy gửi thêm message trống lên server.
Để làm được điều này, thêm 2 hàm sau vào trong code của bạn: một để giữ kết nối, một để hủy kết nối vừa gửi. Nếu sử dụng trick này, bạn có thể kiểm soát thời gian timeout.
Thêm timerId…
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
vartimerID=0;
functionkeepAlive(){
vartimeout=15000;
if(webSocket.readyState==webSocket.OPEN){
webSocket.send('');
}
timerId=setTimeout(keepAlive,timeout);
}
functioncancelKeepAlive(){
if(timerId){
cancelTimeout(timerId);
}
}
Hàm keepAlive() cần được thêm vào cuối của hàm onOpen() của kết nối websocket, và chèn hàm cancelKeepAlive() vào cuối cùng của hàm onClose().
42. Hãy luôn nhớ rằng toán tử nguyên thủy của Javascript có thể nhanh hơn việc gọi hàm.
43. Hãy code chuẩn convention hơn. Minify nó khi deploy
Hãy sử dụng JSLint và minifier nó(ví dụ JSMin…) trước khi chạy code trên môi trường production. Hãy tập code chuẩn convention, tuân theo một convention code nào đó, có thể bây giờ bạn cảm thấy khó chịu khi phải tuân thủ convention nhưng một ngày nào đó việc xem lại mình đã code gì hay debug trên nó cũng trở nên dễ chịu hơn. Code được minify sẽ giảm bớt dung lượng và trở nên nhẹ hơn.