HomeLập trìnhJavaScriptMọi thư bạn...

Mọi thư bạn cân biêt


Một vài tuần trước, tôi đã tweet câu hỏi phỏng vấn này:

*** Trả lời câu hỏi trong đầu của bạn bây giờ trước khi bạn tiếp tục ***

Khoảng một nửa số câu trả lời cho Tweet là sai. Câu trả lời là KHÔNG PHẢI V8 (hoặc các máy ảo khác)!! Mặc dù nổi tiếng với cái tên “Bộ hẹn giờ JavaScript”, các chức năng như setTimeoutsetInterval không phải là một phần của thông số kỹ thuật ECMAScript hoặc bất kỳ triển khai công cụ JavaScript nào. Các chức năng hẹn giờ được triển khai bởi các trình duyệt và việc triển khai chúng sẽ khác nhau giữa các trình duyệt khác nhau. Bộ hẹn giờ cũng được triển khai nguyên bản bởi chính thời gian chạy Node.js.

Trong các trình duyệt, các chức năng hẹn giờ chính là một phần của Window giao diện, có một vài chức năng và đối tượng khác. Giao diện đó làm cho tất cả các phần tử của nó có sẵn trên toàn cầu trong phạm vi JavaScript chính. Đây là lý do tại sao bạn có thể thực hiện setTimeout trực tiếp trong bảng điều khiển của trình duyệt của bạn.

Trong Node, bộ hẹn giờ là một phần của global đối tượng, hoạt động tương tự như đối tượng của trình duyệt Window giao diện. Bạn có thể xem mã nguồn của bộ hẹn giờ trong Node tại đây.

Một số người có thể nghĩ rằng đây là một câu hỏi phỏng vấn tồi – tại sao biết điều này lại quan trọng?! Là một nhà phát triển JavaScript, tôi nghĩ bạn nên biết điều này bởi vì nếu không, đó có thể là dấu hiệu cho thấy bạn không hoàn toàn hiểu cách V8 (và các máy ảo khác) tương tác với trình duyệt và Node.

Chúng ta hãy làm một vài ví dụ và thử thách về chức năng hẹn giờ, phải không?

Cập nhật: Bài viết này hiện là một phần trong “Giới thiệu đầy đủ về Node.js” của tôi.
Bạn có thể đọc phiên bản cập nhật của nó tại đây.

Trì hoãn việc thực hiện một chức năng

Các hàm hẹn giờ là các hàm bậc cao hơn có thể được sử dụng để trì hoãn hoặc lặp lại việc thực thi các hàm khác (mà chúng nhận làm đối số đầu tiên).

Đây là một ví dụ về trì hoãn:

// example1.js
setTimeout(
  () => {
    console.log('Hello after 4 seconds');
  },
  4 * 1000
);

Ví dụ này sử dụng setTimeout để trì hoãn việc in lời chào trong 4 giây. Lập luận thứ hai để setTimeout là độ trễ (tính bằng ms). Đây là lý do tại sao tôi nhân 4 với 1000 để biến nó thành 4 giây.

Đối số đầu tiên để setTimeout là chức năng mà việc thực thi sẽ bị trì hoãn.

Nếu bạn thực hiện example1.js tập tin với node lệnh, Node sẽ tạm dừng trong 4 giây và sau đó nó sẽ in thông báo chào mừng (và thoát sau đó).

Lưu ý rằng đối số đầu tiên để setTimeout chỉ là một chức năng thẩm quyền giải quyết. Nó không phải là một chức năng nội tuyến như những gì example1.js có. Đây là ví dụ tương tự mà không sử dụng hàm nội tuyến:

const func = () => {
  console.log('Hello after 4 seconds');
};
setTimeout(func, 4 * 1000);

Vượt qua đối số

Nếu chức năng sử dụng setTimeout để trì hoãn việc thực thi của nó chấp nhận bất kỳ đối số nào, chúng ta có thể sử dụng các đối số còn lại cho setTimeout chính nó (sau phần 2 mà chúng ta đã học cho đến nay) để chuyển tiếp các giá trị đối số cho hàm bị trì hoãn.

// For: func(arg1, arg2, arg3, ...)
// We can use: setTimeout(func, delay, arg1, arg2, arg3, ...)

Đây là một ví dụ:

// example2.js
const rocks = who => {
  console.log(who + ' rocks');
};
setTimeout(rocks, 2 * 1000, 'Node.js');

Các rocks chức năng trên, bị trễ 2 giây, chấp nhận một who lập luận và setTimeout cuộc gọi chuyển tiếp giá trị “Node.js” như thể who tranh luận.

Đọc thêm  JavaScript là gì? Định nghĩa về ngôn ngữ lập trình JS

thi hành example2.js với node lệnh sẽ in ra “Đá Node.js” sau 2 giây.

Thử thách hẹn giờ #1

Sử dụng những gì bạn đã học cho đến nay về setTimeoutin 2 thông báo sau sau độ trễ tương ứng của chúng.

  • In tin nhắn “Xin chào sau 4 giây” sau 4 giây
  • In tin nhắn “Xin chào sau 8 giây” sau 8 giây.

Hạn chế:
Bạn chỉ có thể xác định một hàm duy nhất trong giải pháp của mình, bao gồm các hàm nội tuyến. Điều này có nghĩa là nhiều setTimeout các cuộc gọi sẽ phải sử dụng chính xác chức năng tương tự.

Dung dịch

Đây là cách tôi giải quyết thử thách này:

// solution1.js
const theOneFunc = delay => {
  console.log('Hello after ' + delay + ' seconds');
};
setTimeout(theOneFunc, 4 * 1000, 4);
setTimeout(theOneFunc, 8 * 1000, 8);

tôi đã làm theOneFunc nhận được delay đối số và sử dụng giá trị của điều đó delay đối số trong tin nhắn được in. Bằng cách này, hàm có thể in các thông báo khác nhau dựa trên bất kỳ giá trị độ trễ nào mà chúng ta chuyển cho nó.

sau đó tôi đã sử dụng theOneFunc trong hai setTimeout cuộc gọi, một cuộc gọi kích hoạt sau 4 giây và một cuộc gọi khác kích hoạt sau 8 giây. Cả hai điều này setTimeout cuộc gọi cũng nhận được một lần thứ 3 lập luận để đại diện cho delay lập luận cho theOneFunc.

thực hiện solution1.js tập tin với node lệnh sẽ in ra các yêu cầu thử thách, tin nhắn đầu tiên sau 4 giây và tin nhắn thứ hai sau 8 giây.

Lặp lại việc thực hiện một chức năng

Điều gì sẽ xảy ra nếu tôi yêu cầu bạn in một tin nhắn cứ sau 4 giây, mãi mãi?

Trong khi bạn có thể đặt setTimeout trong một vòng lặp, API hẹn giờ cung cấp setInterval cũng hoạt động, điều này sẽ hoàn thành yêu cầu làm một việc gì đó mãi mãi.

Đây là một ví dụ về setInterval:

// example3.js
setInterval(
  () => console.log('Hello every 3 seconds'),
  3000
);

Ví dụ này sẽ in tin nhắn của nó cứ sau 3 giây. thi hành example3.js với node lệnh sẽ khiến Node in thông báo này mãi mãi, cho đến khi bạn kết thúc quá trình (với CTRL+C).

Hủy hẹn giờ

Bởi vì việc gọi hàm hẹn giờ lên lịch cho một hành động, nên hành động đó cũng có thể bị hủy trước khi nó được thực thi.

Một cuộc gọi đến setTimeout trả về một “ID” hẹn giờ và bạn có thể sử dụng ID hẹn giờ đó với một clearTimeout gọi để hủy hẹn giờ đó. Đây là một ví dụ:

// example4.js
const timerId = setTimeout(
  () => console.log('You will not see this one!'),
  0
);
clearTimeout(timerId);

Bộ đếm thời gian đơn giản này được cho là kích hoạt sau ms (làm cho nó ngay lập tức), nhưng nó sẽ không xảy ra vì chúng tôi đang nắm bắt timerId giá trị và hủy bỏ nó ngay sau đó với một clearTimeout cuộc gọi.

Khi chúng tôi thực hiện example4.js với node lệnh, Nút sẽ không in bất cứ thứ gì và quá trình sẽ thoát ra.

Nhân tiện, trong Node.js, có một cách khác để làm setTimeout với bệnh đa xơ cứng. API hẹn giờ Node.js có một chức năng khác được gọi là setImmediatevà về cơ bản nó giống như một setTimeout với một ms nhưng chúng tôi không phải chỉ định độ trễ ở đó:

setImmediate(
  () => console.log('I am equivalent to setTimeout with 0 ms'),
);

Các setImmediate chức năng không có sẵn trong tất cả các trình duyệt. Đừng sử dụng nó cho mã front-end.

Giống như clearTimeoutCũng có một clearInterval chức năng, làm điều tương tự nhưng đối với setInerval cuộc gọi, và cũng có một clearImmediate gọi là tốt.

Độ trễ hẹn giờ không phải là một điều được đảm bảo

Trong ví dụ trước, bạn có nhận thấy cách thực hiện một cái gì đó với setTimeout sau đó ms không có nghĩa là thực thi nó ngay lập tức (sau dòng setTimeout), mà là thực thi nó ngay lập tức sau mọi thứ khác trong tập lệnh (bao gồm cả lệnh gọi ClearTimeout)?

Đọc thêm  Báo cáo trả về JavaScript

Hãy để tôi làm rõ điểm này với một ví dụ. Đây là một cách đơn giản setTimeout cuộc gọi sẽ kích hoạt sau nửa giây, nhưng nó sẽ không:

// example5.js
setTimeout(
  () => console.log('Hello after 0.5 seconds. MAYBE!'),
  500,
);
for (let i = 0; i < 1e10; i++) {
  // Block Things Synchronously
}

Ngay sau khi xác định bộ đếm thời gian trong ví dụ này, chúng tôi chặn thời gian chạy một cách đồng bộ với một for vòng. Các 1e101 với 10 số không ở phía trước của nó, vì vậy vòng lặp là một 10 Vòng lặp hàng tỷ tích tắc (về cơ bản mô phỏng một CPU bận rộn). Nút không thể làm gì trong khi vòng lặp này đang tích tắc.

Tất nhiên, đây là một điều rất tồi tệ trong thực tế, nhưng nó sẽ giúp bạn hiểu điều đó ở đây. setTimeout sự chậm trễ không phải là một điều được đảm bảo, mà là một tối thiểu Điều. Các 500 ms có nghĩa là độ trễ tối thiểu là 500 bệnh đa xơ cứng. Trên thực tế, kịch bản sẽ mất nhiều thời gian hơn để in dòng lời chào của nó. Nó sẽ phải đợi vòng lặp chặn kết thúc trước.

Thử thách hẹn giờ #2

Viết đoạn lệnh để in thông báo “Chào thế giới” mỗi giây, nhưng chỉ 5 lần. Sau 5 lần, tập lệnh sẽ in thông báo “Xong” và để quá trình Node thoát ra.

Hạn chế: Bạn không thể sử dụng một setTimeout kêu gọi thử thách này.
Gợi ý: Bạn cần một bộ đếm.

Dung dịch

Đây là cách tôi giải quyết vấn đề này:

let counter = 0;
const intervalId = setInterval(() => {
  console.log('Hello World');
  counter += 1;
if (counter === 5) {
    console.log('Done');
    clearInterval(intervalId);
  }
}, 1000);

tôi bắt đầu một counter giá trị như và sau đó bắt đầu một setInterval gọi chụp id của nó.

Chức năng trì hoãn sẽ in thông báo và tăng bộ đếm mỗi lần. Bên trong chức năng trì hoãn, một if tuyên bố sẽ kiểm tra xem chúng tôi đang ở 5 lần cho đến bây giờ. Nếu vậy, nó sẽ in “Xong” và xóa khoảng thời gian bằng cách sử dụng intervalId hằng số. Độ trễ khoảng thời gian là 1000 bệnh đa xơ cứng.

Chính xác thì ai “gọi” các chức năng bị trì hoãn?

Khi bạn sử dụng JavaScript this từ khóa bên trong một chức năng thông thường, như thế này:

function whoCalledMe() {
  console.log('Caller is', this);
}

Giá trị bên trong this từ khóa sẽ đại diện cho người gọi của chức năng. Nếu bạn xác định chức năng trên bên trong Node REPL, người gọi sẽ là global vật. Nếu bạn xác định chức năng bên trong bảng điều khiển của trình duyệt, người gọi sẽ là window vật.

Hãy định nghĩa hàm dưới dạng một thuộc tính trên một đối tượng để làm cho điều này rõ ràng hơn một chút:

const obj = { 
  id: '42',
  whoCalledMe() {
    console.log('Caller is', this);
  }
};
// The function reference is now: obj.whoCallMe

Bây giờ khi bạn gọi obj.whoCallMe chức năng sử dụng trực tiếp tham chiếu của nó, người gọi sẽ là obj đối tượng (được xác định bởi id của nó):

1*oo6w6C8omvxjxSwK_FJsag

Bây giờ, câu hỏi là, người gọi sẽ là gì nếu chúng ta chuyển tham chiếu của obj.whoCallMe đến một setTimetout cuộc gọi?

// What will this print??
setTimeout(obj.whoCalledMe, 0);

Ai sẽ là người gọi trong trường hợp đó?

Câu trả lời là khác nhau dựa trên nơi chức năng hẹn giờ được thực thi. Bạn chỉ đơn giản là không thể phụ thuộc vào người gọi là ai trong trường hợp đó. Bạn mất quyền kiểm soát người gọi vì việc triển khai bộ đếm thời gian sẽ là chức năng gọi hàm của bạn ngay bây giờ. Nếu bạn kiểm tra nó trong Node REPL, bạn sẽ nhận được một Timetout đối tượng là người gọi:

1*du_RKr4vPNh1irFRPR92EA

Lưu ý rằng điều này chỉ quan trọng nếu bạn đang sử dụng JavaScript this từ khóa bên trong các hàm thông thường. Bạn hoàn toàn không cần lo lắng về người gọi nếu bạn đang sử dụng các hàm mũi tên.

Đọc thêm  Tres forms de factorizar un numero en JavaScript

Thử thách hẹn giờ #3

Viết đoạn lệnh in liên tục thông báo “Chào thế giới” với độ trễ khác nhau. Bắt đầu với độ trễ 1 giây và sau đó tăng độ trễ thêm 1 giây mỗi lần. Lần thứ hai sẽ có độ trễ là 2 giây. Lần thứ ba sẽ có độ trễ là 3 giây, v.v.

Bao gồm độ trễ trong thông báo được in. Sản lượng dự kiến ​​trông giống như:

Hello World. 1
Hello World. 2
Hello World. 3
...

Hạn chế: Bạn chỉ có thể sử dụng const để xác định các biến. bạn không thể sử dụng let hoặc var.

Dung dịch

Vì độ trễ là một biến trong thử thách này nên chúng tôi không thể sử dụng setInterval ở đây, nhưng chúng ta có thể tự tạo khoảng thời gian thực thi bằng cách sử dụng setTimeout trong một cuộc gọi đệ quy. Hàm được thực thi đầu tiên với setTimeout sẽ tạo một bộ đếm thời gian khác, v.v.

Ngoài ra, vì chúng ta không thể sử dụng let/var, nên chúng ta không thể có bộ đếm để tăng độ trễ trong mỗi lệnh gọi đệ quy, nhưng thay vào đó, chúng ta có thể sử dụng các đối số hàm đệ quy để tăng trong khi gọi đệ quy.

Đây là một cách có thể để giải quyết thách thức này:

const greeting = delay =>
  setTimeout(() => {
    console.log('Hello World. ' + delay);
    greeting(delay + 1);
  }, delay * 1000);
greeting(1);

Thử thách hẹn giờ #4

Viết đoạn lệnh in liên tục thông báo “Chào thế giới” với cùng một khái niệm độ trễ khác nhau như thử thách số 3, nhưng lần này, theo nhóm 5 thông báo cho mỗi khoảng thời gian trễ chính. Bắt đầu với độ trễ 100 mili giây cho 5 tin nhắn đầu tiên, sau đó là 200 mili giây cho 5 tin nhắn tiếp theo, sau đó là 300 mili giây, v.v.

Đây là cách tập lệnh nên hoạt động:

  • Tại thời điểm 100 mili giây, tập lệnh sẽ bắt đầu in “Xin chào thế giới” và thực hiện điều đó 5 lần với khoảng thời gian 100 mili giây. Thông báo đầu tiên sẽ xuất hiện ở 100ms, thông báo thứ 2 ở 200ms, v.v.
  • Sau 5 thông báo đầu tiên, tập lệnh sẽ tăng độ trễ chính lên 200 mili giây. Vì vậy, tin nhắn thứ 6 sẽ được in ở 500ms + 200ms (700ms), tin nhắn thứ 7 sẽ được in ở 900ms, tin nhắn thứ 8 sẽ được in ở 1100ms, v.v.
  • Sau 10 thông báo, tập lệnh sẽ tăng độ trễ chính lên 300 mili giây. Vì vậy, tin nhắn thứ 11 nên được in ở 500ms + 1000ms + 300ms (18000ms). Thông báo thứ 12 sẽ được in ở tốc độ 21000 mili giây, v.v.
  • Tiếp tục mô hình mãi mãi.

Bao gồm độ trễ trong thông báo được in. Đầu ra dự kiến ​​trông như thế này (không có nhận xét):

Hello World. 100  // At 100ms
Hello World. 100  // At 200ms
Hello World. 100  // At 300ms
Hello World. 100  // At 400ms
Hello World. 100  // At 500ms
Hello World. 200  // At 700ms
Hello World. 200  // At 900ms
Hello World. 200  // At 1100ms
...

Hạn chế: Bạn chỉ có thể sử dụng setInterval cuộc gọi (không phải setTimeout) và bạn chỉ có thể sử dụng MỘT câu lệnh if.

Dung dịch

Bởi vì chúng ta chỉ có thể sử dụng setInterval cuộc gọi, chúng tôi cũng sẽ cần đệ quy ở đây để tăng độ trễ của lần tiếp theo setInterval cuộc gọi. Ngoài ra, chúng ta cần một câu lệnh if để kiểm soát việc thực hiện điều đó chỉ sau 5 lần gọi hàm đệ quy đó.

Đây là một giải pháp khả thi:

let lastIntervalId, counter = 5;
const greeting = delay => {
  if (counter === 5) {
    clearInterval(lastIntervalId);
    lastIntervalId = setInterval(() => {
      console.log('Hello World. ', delay);
      greeting(delay + 100);
    }, delay);
    counter = 0;
  }
counter += 1;
};
greeting(100);

Cảm ơn vì đã đọc.

Nếu bạn mới bắt đầu tìm hiểu Node.js, gần đây tôi đã xuất bản một khóa học bước đầu tiên tại Pluralsightxem thử:

1*OoRpYXrRivoSnQTscAjCMw
https://jscomplete.com/c/nodejs-getting-started



Zik.vn – Biên dịch & Biên soạn Lại

spot_img

Create a website from scratch

Just drag and drop elements in a page to get started with Newspaper Theme.

Buy Now ⟶

Bài viết liên quang

DMCA.com Protection Status