2012-06-27 18 views
18

Tôi hiểu điều cơ bản về không đồng bộ-Ness: mọi thứ không thực thi tuần tự. Và tôi hiểu có điều gì đó rất mạnh mẽ về điều đó ... bị cáo buộc. Nhưng đối với cuộc sống của tôi, tôi không thể quấn đầu quanh mã. Chúng ta hãy nhìn vào mã async Node.JS mà tôi CÓ VĂN BẢN ... nhưng không thực sự có được.Hiểu mã không đồng bộ trong các điều khoản của Layman

function newuser(response, postData) { 
    console.log("Request handler 'newuser' was called."); 
    var body = '<html>' + 
     '<head>' + 
     '<meta http-equiv="Content-Type" content="text/html; ' + 
     'charset=UTF-8" />' + 
     '</head>' + 
     '<body>' + 
     '<form action=" /thanks" method="post">' + 
     '<h1> First Name </h1>' + 
     '<textarea name="text" rows="1" cols="20"></textarea>' + 
     '<h1> Last Name </h1>' + 
     '<textarea name="text" rows="1" cols="20"></textarea>' + 
     '<h1> Email </h1>' + 
     '<textarea name="text" rows="1" cols="20"></textarea>' + 
     '<input type="submit" value="Submit text" />' + 
     '</body>' + 
     '</html>'; 
    response.writeHead(200, { "Content-Type": "text/html" }); 
    response.write(body); 
    response.end(); 
} 

Phản hồi đến từ đâu? postData? Tại sao tôi không thể xác định một biến trong "gọi lại" này và sau đó sử dụng nó bên ngoài của cuộc gọi lại? Có cách nào để có một vài thứ được tuần tự sau đó phần còn lại của chương trình không đồng bộ?

Trả lời

41

Tôi không chắc nơi chức năng này đang được sử dụng, nhưng điểm gọi lại là bạn chuyển chúng vào một số hàm chạy không đồng bộ; nó lưu trữ gọi lại của bạn, và khi chức năng đó được thực hiện với bất cứ điều gì nó cần phải làm, nó sẽ gọi gọi lại của bạn với các thông số cần thiết. Một ví dụ từ front-to-back có lẽ là tốt nhất.

Hãy tưởng tượng chúng tôi có một khuôn khổ và trong đó có một hoạt động chạy trong một thời gian dài, tìm nạp một số dữ liệu từ cơ sở dữ liệu.

function getStuffFromDatabase() { 
    // this takes a long time 
}; 

Vì chúng tôi không muốn nó chạy đồng bộ, chúng tôi sẽ cho phép người dùng chuyển qua gọi lại.

function getStuffFromDatabase(callback) { 
    // this takes a long time 
}; 

Chúng tôi sẽ mô phỏng mất nhiều thời gian với cuộc gọi đến setTimeout; chúng tôi cũng giả vờ rằng chúng tôi có một số dữ liệu từ cơ sở dữ liệu, nhưng chúng tôi sẽ chỉ mã hóa một giá trị chuỗi.

function getStuffFromDatabase(callback) { 
    setTimeout(function() { 
    var results = "database data"; 
    }, 5000); 
}; 

Cuối cùng, khi chúng tôi có các dữ liệu, chúng tôi sẽ gọi gọi lại ban cho chúng ta bởi người sử dụng chức năng của khung.

function getStuffFromDatabase(callback) { 
    setTimeout(function() { 
    var results = "database data"; 
    callback(results); 
    }, 5000); 
}; 

Là một người sử dụng của khuôn khổ này, bạn muốn làm điều gì đó như thế này để sử dụng chức năng:

getStuffFromDatabase(function(data) { 
    console.log("The database data is " + data); 
}); 

Vì vậy, như bạn có thể nhìn thấy data (giống như responsepostData trong ví dụ của bạn) đến từ hàm mà bạn chuyển số gọi lại vào; nó cung cấp dữ liệu đó cho bạn khi nó biết dữ liệu đó nên là gì.

Lý do bạn không thể đặt giá trị trong gọi lại và sử dụng giá trị đó bên ngoài cuộc gọi lại là do chính cuộc gọi lại không xảy ra cho đến sau này.

// executed immediately executed sometime in the future 
//  |     |  by getStuffFromDatabase 
//  v     v 
getStuffFromDatabase(function(data) { 
    var results = data; // <- this isn't available until sometime in the future! 
}); 

console.log(results); // <- executed immediately 

Khi số console.log chạy, nhiệm vụ var results chưa xảy ra!

+0

Từ điểm kỹ thuật bạn nói đúng, nhưng những gì bạn bỏ lỡ là "tại sao bạn muốn thực hiện cuộc gọi lại ngay từ đầu". Đó là những gì làm cho async trở nên rất quan trọng. – jcolebrand

+3

Tôi sẽ không nói rằng tôi sẽ không đọc nó một hay hai lần nữa - nhưng đó có lẽ là giải thích tốt nhất mà người ta có thể đưa ra mà không cần phải ở đây về thể chất, heh. – PinkElephantsOnParade

+1

Tôi nghĩ rằng đây là một lời giải thích tuyệt vời cho sự hiểu biết cách hoạt động của callbacks - cảm ơn vì nó! – wmock

6

Bạn có một vài câu hỏi không liên quan ở đây:

1) Sức mạnh của async là việc có thể làm nhiều thứ cùng một lúc mà không cần khóa các chủ đề chính. Trong nút và js nói chung, điều này đặc biệt áp dụng cho các yêu cầu tệp ajax. Điều này có nghĩa là tôi có thể kích hoạt một số cuộc gọi không đồng bộ để truy xuất các tệp và không khóa chủ đề chính trong khi nó hiển thị nội dung. Khung ưa thích của tôi là jQuery, có thuận tiện $ .Deferred kết thúc tốt đẹp và chuẩn hóa các cuộc gọi không đồng bộ để sử dụng jQuery.

2) phản hồi và postData đến từ phương thức gốc. Không có gì huyền diệu ở đây, đó là một cuộc gọi hàm bình thường, vì vậy các giá trị của chúng được tạo ra ở nơi khác và được chuyển vào lời gọi này. Tùy thuộc vào khung nút nào bạn có, chữ ký chính xác của phương thức của bạn sẽ thay đổi.

3) Bạn có thể xác định biến toàn cục trong hàm gọi lại của mình nếu biến đó được sắp xếp đúng. Dường như bạn cần trợ giúp tìm hiểu phạm vi là gì. Dưới đây là một số liên kết

http://www.digital-web.com/articles/scope_in_javascript/

http://robertnyman.com/2008/10/09/explaining-javascript-scope-and-closures/

4) Khi bạn đi async, bạn không bao giờ có thể quay trở lại, tuy nhiên, bằng cách tận dụng lời hứa và các đối tượng chậm như với jQuery Deferreds bạn có thể chờ đợi trong vài asyncs để hoàn thành trước khi tiếp tục thực hiện của bạn trong một async khác. Trì hoãn là bạn của bạn.

http://api.jquery.com/category/deferred-object/

+0

Bằng cách nào đó đã bỏ lỡ câu trả lời rất hay này lần đầu tiên tôi xem xét: +1 – PinkElephantsOnParade

+0

Chết tiệt đúng. Tôi thật tuyệt vời! –

+2

Tôi hoan nghênh sự tự tin của bạn – PinkElephantsOnParade

1

Dường như bạn đang làm việc thông qua các Node Beginner Book. Tôi khuyến khích bạn làm việc thông qua toàn bộ cuốn sách, nó thực sự là một giới thiệu tuyệt vời. Nếu bạn đang cố gắng hiểu rõ hơn về Javascript, video của Douglas Crockford trên YouTube là một tổng quan tuyệt vời: 1, 2.

Đoạn mã bạn đã đăng không có đủ ngữ cảnh để tôi thực sự giúp bạn. response là một tham số mà bạn đang chuyển đến hàm của bạn, nó không xuất phát từ postData. Nếu bạn đang làm việc với mã theo cách mà Node Beginner Book gợi ý, có lẽ bạn đang chuyển trả lời cho hàm newuser của bạn xuống từ hàm createServer, là một phần của mô-đun http đi kèm với Node.

Bạn không thể xác định một biến trong gọi lại và sau đó sử dụng nó trong gọi lại vì Javascript bị lexically scoped. Đây là một Stack Overflow post về chủ đề phạm vi của Javascript. Video đầu tiên của Doug Crockford mà tôi đăng cũng có một lời giải thích tuyệt vời về các quy tắc phạm vi của Javascript.

Javascript không nhất thiết là không đồng bộ. Nó chỉ đơn giản cung cấp các hàm ẩn danh là các bao đóng, là một công cụ hữu ích để dễ dàng triển khai thực hiện logic không đồng bộ. Một lần nữa, Node Beginner Book cho thấy một ví dụ tốt về viết mã đồng bộ với Node (không phải những gì bạn muốn), sau đó viết lại nó để làm cho nó không đồng bộ.

Các vấn đề liên quan