2013-08-08 8 views
6

Môi trường javascript của nút có phải là luồng đơn, hay mọi thứ xảy ra cùng một lúc? Hoặc (nhiều khả năng) không làm những câu lệnh đó giải thích những gì đang xảy ra với nút.Giải thích các cuộc gọi lại của nút và luồng đơn

Tôi mới tham gia nút và cố gắng hiểu cách thức xử lý cuộc gọi lại. Việc googling về chủ đề của tôi không được chứng minh hiệu quả và dường như có nhiều đối tượng sử dụng các cụm từ như "chủ đề, khóa và chuỗi đơn" với ngữ cảnh khác nhau cho từng đối tượng và tôi không có đủ kinh nghiệm với nút để phân tích cú pháp chính xác những gì tôi đang đọc.

Từ những gì tôi đã đọc, môi trường thực thi javascript của nút là, giống như một trình duyệt, một chuỗi. Đó là, mặc dù tất cả mọi thứ được thiết kế xung quanh callbacks không đồng bộ, tất cả mọi thứ xảy ra theo một thứ tự xác định, và không bao giờ có hai chủ đề sửa đổi cùng một biến hoặc chạy báo cáo cùng một lúc. Tôi cũng đã đọc điều này có nghĩa là một lập trình viên-người sử dụng nút không phải lo lắng về khóa ngữ nghĩa.

Nếu anh ở dưới trình duyệt đất đai và sử dụng một trong các thư viện javascript phổ biến để thiết lập một callback phi dom-event-handler, một cái gì đó giống như

console.log("Here"); 
$.each([1,2,3],function(){ 
    console.log("-- inside the callback --"); 
}); 
console.log("There"); 

đầu ra của tôi là luôn

Here 
-- inside the callback -- 
-- inside the callback -- 
-- inside the callback -- 
There 

Tuy nhiên, nếu tôi làm điều gì đó như thế này với gọi lại trong nút js (chạy nó dưới dạng tập lệnh shell từ dòng lệnh)

var function example() 
{ 
    var fs = require('fs'); 
    console.log("Here"); 
    fs.readdir('/path/to/folder', function(err_read, files){ 
     console.log('-- inside the callback --');    
    }); 
    console.log("There"); 
    for(var i=0;i<10000;i++) 
    { 
     console.log('.'); 
    } 
} 
example(); 
console.log("Reached Top"); 

tôi liên tục (dường như - xem "không nhiều kinh nghiệm" ở trên) có được kết quả như thế này

Here 
There 
. 
. (repeat 10,000 times) 
Reached Top 
-- inside the callback --  

Đó là, nút kết thúc thực hiện các chức năng example trước khi gọi gọi lại.

Đây có phải là hành vi xác định trong nút không? Hoặc có lần gọi lại sẽ được gọi trước khi chức năng example kết thúc không? Hoặc nó sẽ phụ thuộc vào việc thực hiện trong thư viện bằng cách sử dụng gọi lại?

Tôi hiểu ý tưởng đằng sau nút là viết mã dựa trên sự kiện - nhưng tôi đang cố hiểu nút nào thực sự đang hoạt động và hành vi nào có thể dựa vào và điều gì không thể.

+1

có thể trùng lặp của [NodeJS thực sự là một luồng đơn?] (Http://stackoverflow.com/questions/7018093/is-nodejs-really-single-threaded) hoặc [NodeJS event loop] (http: // stackoverflow .com/questions/10680601/nodejs-event-loop) – Bergi

+1

Đối với những người trùng lặp - tôi đã thấy câu hỏi đó trước khi hỏi. Nó trả lời câu hỏi "Liệu nút chính nó có sử dụng chủ đề nội bộ" hay không. Câu hỏi của tôi là nhiều hơn "Mô hình thực thi gọi lại của nút trong vùng người dùng javascript" là gì.Sự khác biệt quan trọng, nhưng quan trọng) –

Trả lời

1

Trong trường hợp này, bạn đang gọi một hàm đang thực hiện IO và không đồng bộ. Đó là lý do tại sao bạn đang nhìn thấy đầu ra theo cách của bạn.

Bởi vì phần còn lại của mã của bạn đang thực hiện nội tuyến - trên một chuỗi thực hiện duy nhất, nó được hoàn thành trước khi các sự kiện IO được cung cấp một cơ hội để thực hiện theo cách của họ vào vòng lặp sự kiện.

Tôi có thể mong đợi hành vi này, nhưng không phụ thuộc vào nó với độ chắc chắn tuyệt đối vì nó phụ thuộc vào việc triển khai thư viện bằng cách sử dụng gọi lại. Một người triển khai (xấu, xấu) có thể đang thực hiện một yêu cầu đồng bộ để xem liệu có bất kỳ công việc nào được thực hiện và, nếu không, gọi lại ngay lập tức. (Hy vọng rằng bạn sẽ không bao giờ thấy điều này, nhưng ...).

2

Môi trường javascript của nút có phải là luồng đơn hay mọi thứ xảy ra cùng một lúc không?

Nút có mô hình thực hiện chương trình luồng đơn, nghĩa là chỉ một lệnh sẽ được thực hiện bất kỳ lúc nào trong một quy trình nút. Việc thực hiện sẽ tiếp tục cho đến khi chương trình mang lại sự kiểm soát. Điều này có thể xảy ra ở cuối mã chương trình hoặc khi cuộc gọi lại kết thúc.

Trong trường hợp thứ nhất:

console.log("Here"); 
$.each([1,2,3],function(){ 
    console.log("-- inside the callback --"); 
}); 
console.log("There"); 

họ chính là một thực tế rằng $.each sử dụng callbacks đồng bộ, vì vậy hiệu quả mà họ gọi đó là callbacks theo thứ tự xác định.

Bây giờ trong trường hợp thứ hai, fs.readdir sử dụng gọi lại không đồng bộ - nó đặt cuộc gọi chờ đợi sự kiện được kích hoạt (nghĩa là khi đọc thư mục kết thúc). Điều đó có thể xảy ra bất cứ lúc nào. Tuy nhiên, chức năng gọi điện không có khả năng kiểm soát nên example sẽ luôn kết thúc trước khi bất kỳ cuộc gọi lại nào được gọi.

Trong một câu: Tất cả mã của hàm/phạm vi toàn cục được thực thi trước bất kỳ hàm gọi lại nào được xác định trong hàm/phạm vi toàn cục đó.

+0

Tôi hơi bối rối về tuyên bố * Tuy nhiên, nó không mang lại khả năng kiểm soát *. Ai là "nó" trong trường hợp này? Hàm 'example'? Thư viện? Nút chính nó? Ngoài ra, lại: "kiểm soát năng suất", là có một tuyên bố tôi có thể sử dụng trong chương trình của tôi để kiểm soát năng suất? Hoặc là kiểm soát ra khỏi bàn tay của người lập trình khách hàng cuối? –

+0

@AlanStorm chức năng thư viện (và, bằng cách mở rộng 'example'). Nói cách khác tất cả các mã sẽ thực hiện theo thứ tự với ngoại lệ của * không đồng bộ * callbacks. – soulcheck

+0

Tôi đã đề cập đến nó, bởi vì có các khuôn khổ với một chiến lược sinh lợi khác nhau: [gevent] (http://www.gevent.org/) mang lại các cuộc gọi không đồng bộ. – soulcheck

1

Tôi muốn thêm một chút vào câu trả lời của @ dc5. Trên đó là website họ mô tả nút như

Node.js sử dụng một

Sự kiện này thúc đẩy một phần sự kiện-driven, non-blocking I/O mẫu là rất đáng kể. Nó thường xóa bỏ những nghi ngờ của tôi khi tôi gặp khó khăn trong việc hiểu mô hình thực hiện của các chương trình nút.

Vì vậy, dùng ví dụ của bạn những gì đang xảy ra là:

  1. Đây được in ra cửa sổ Console.

  2. Cuộc gọi không đồng bộ được thực hiện cho các tệp.

  3. Nút gắn trình nghe với cuộc gọi không đồng bộ.

  4. Tiếp tục xuống dòng thực hiện và Đã in.

Bây giờ nó có thể là cuộc gọi async được hoàn thành trước mảnh hiện tại của mã đó đã được thực hiện nhưng js nút hoàn thành nhiệm vụ trong tầm tay và sau đó trả về để phục vụ các cuộc gọi async.

Vì vậy, thay vì chờ đợi bất cứ điều gì nó tiếp tục thực hiện trong dòng. Đó là lý do tại sao vòng lặp thực thi nút js không bao giờ nhàn rỗi.