2015-01-16 10 views
7

Tôi khá mới đối với JavaScript và tôi đang làm việc trong nút yêu cầu hiểu rõ về lập trình async và thiết kế gọi lại. Tôi đã thấy rằng việc sử dụng các hàm được nhúng rất dễ thực hiện ngay cả khi các cuộc gọi lại của bạn có nhiều cấp độ sâu. Cuộc gọi lại được nhúng của bạn chỉ kết thúc là đóng cửa.Cách triển khai chức năng gọi lại có thể sử dụng

Tuy nhiên, khi bạn có nhiều lớp gọi lại trong đó nhiều cuộc gọi lại giống nhau trên các tuyến thực thi, bạn sẽ kết thúc viết lại nhiều mã gọi lại nhiều lần trong các chuỗi gọi lại riêng biệt. Ví dụ, nếu các định nghĩa mycb1 và mycb2 bên dưới được di chuyển ra ngoài A, chúng không còn có quyền truy cập ngầm định vào các biến của A và do đó, không còn hoạt động như các bao đóng nữa.

Ví dụ với định nghĩa được nhúng khi chúng hoạt động như các bao đóng.

mod.A=function(){ 
    var mycb1=function(err){ 
    if (!err){ 
     var mycb2=function(err){ 
     cb(err); 
     }; 
     mod.foo2(args,mycb2); 
    } 
    else{cb(err);} 
    }; 
    mod.foo1(args,mycb1); 
} 

mod.foo1 = function(args,cb){ 
    //do some work 
    cb(err); 
}; 

mod.foo2 = function(args,cb){ 
    //do some work 
    cb(err); 
} 
//execute 
mod.A(); 

Tôi muốn làm như sau nhưng có thể thay đổi phạm vi biến cho các chức năng mycb1 và mycb2 để họ có thể được sử dụng như đóng cửa từ nơi nào chúng được gọi. Ví dụ:

var mycb2=function(err){ 
    ... 
    cb(err); 
}; 

var mycb1=function(err){ 
    if (!err){   
    mod.foo2(args,mycb2); //but have it act like a closure to mycb1 
    } 
    else{cb(err);} 
}; 

mod.A=function(){ 
    ... 
    mod.foo1(args,mycb1); //but have it act like a closure to A 
} 

mod.foo1 = function(args,cb){ 
    //do some work 
    cb(err); 
} 

mod.foo2 = function(args,cb){ 
    //do some work 
    cb(err); 
} 

tôi biết rằng tôi có thể thực hiện một thiết kế mà một trong hai bộ biến ở mức mod để họ có thể truy cập vào các chức năng mức mod. Tuy nhiên, điều này dường như phần nào gây ô nhiễm phạm vi mod với biến mà chỉ có thể được sử dụng bởi một vài phương thức của nó. Tôi cũng biết rằng tôi có thể chuyển vào các biến để làm cho chúng có thể truy cập được vào các cuộc gọi lại khi chúng được thực hiện. Tuy nhiên, nếu tôi hiểu JS và callback hoạt động như thế nào, tôi sẽ phải chuyển nó cho fooX và sau đó foo chuyển chúng cho callbacks. Điều đó dường như không phải là một kế hoạch tốt. Phạm vi có thể thay đổi của một hàm được thay đổi để nó hoạt động như một đóng cửa từ điểm thực thi của nó chứ không phải là điểm định nghĩa của nó? Nếu không, cách tốt nhất để mô đun hóa mã gọi lại của bạn để nó có thể được tái sử dụng là gì?

+1

bạn có thể sử dụng hàm Function.bind() để đánh giá các giá trị đã biết vào các cuộc gọi lại có tên trong thời gian chạy. đó là về gần như "đóng cửa từ điểm thực hiện của nó" như nó được, nếu tôi hiểu bạn một cách chính xác. – dandavis

+0

bạn cũng có thể sử dụng lời hứa để duy trì trạng thái mà không đóng quá đông đúc mô-đun – dandavis

+0

Lời khuyên tuyệt vời. Cảm ơn bạn. – rss181919

Trả lời

6

Nói chung, không có xung quanh việc phải tạo một chức năng khác nội dòng có quyền truy cập vào các đóng. Bạn có thể tạo hàm trong dòng bằng cách có một hàm ẩn danh đơn giản chuyển một số đối số đến hàm gọi lại làm tham số trong khi chấp nhận phần còn lại (tức là một hàm một phần) hoặc bằng cách sử dụng Function.bind() để tự tạo một phần chức năng.

Ví dụ, nếu ban đầu bạn có:

function(...) { 
    // closure vars x1, y1 
    foo.bar(function(result) { 
     // do something with x1 and y1 
    }); 
} 

Bạn có thể trích xuất để:

var callback = function(x1, y1, result) { 
    // do something with x1 and y1 
}; 

function(...) { 
    // closure vars x1, y1 

    // option 1: make your own partial function 
    foo.bar(function(result) { return callback(x1, y1, result); }); 
    // with ES6: foo.bar((result) => callback(x1, y1, result); }); 

    // option 2: use Function.bind 
    foo.bar(callback.bind(this, x1, y1);); 
} 
+0

Đây là những gì tôi cần. Cảm ơn bạn đã xây dựng câu trả lời. Nó thực sự giúp một newbie :) – rss181919

1

đây là một ví dụ gọi lại lồng nhau với không đóng cửa và không làm tổ. nó lấy trang được chỉ định, tìm liên kết thứ ba, sau đó hiển thị nguồn của liên kết đó cho người dùng.

trong trường hợp này, khi chạy từ đây trong bảng điều khiển và cho ăn trang chủ, trang đăng xuất là liên kết thứ ba và nội dung của nó được cảnh báo.

tất cả các callbacks là anh chị em, và không có biến trạng thái bên ngoài, chỉ thuần túy chức năng async:

// look ma, no nesting! 
function ajax(a, c) { 
    var e = new XMLHttpRequest; 
    e.onload= ajaxOnload.bind(this, c, e); 
    e.open("GET", a, !0); 
    e.send(); 
    return e 
} 

function ajaxOnload(c, e) { 
    c(e.responseText, e); 
} 

function cbFind3(cb, s){ 
    var t=document.createElement("body"); 
    t.innerHTML=s; 
    var lnk= t.getElementsByTagName("a")[3].href; 
    ajax(lnk, cb);  
} 

function grabThirdLinkSource(url, cb){ 
    ajax(url, cbFind3.bind(this, cb)); 
} 

grabThirdLinkSource("/", alert); 

nó không phải là ví dụ hữu ích nhất, nhưng nó cho thấy làm thế nào để chuỗi chức năng trên invocations với bind (). tôi đã sử dụng vanilla ajax và tránh những lời hứa đơn giản chỉ ra cách phong cách tương tác này thực hiện mà không có bất kỳ biến chứng nào. ngay cả người trợ giúp ajax cũng sử dụng một hàm không lồng nhau để đưa responseText vào callback "core" thay vì sự kiện hoặc toàn bộ đối tượng xhr.

+0

Cảm ơn. Ví dụ của bạn giúp xác nhận những gì mà 2 người dùng trước đó đã đề xuất. Sự thật là tôi muốn buộc gọi lại để thực thi với cùng phạm vi biến mà mã gọi đang thực thi và bạn không thể làm điều đó trong javascript. Bạn có thể sử dụng các hàm một phần hoặc ràng buộc để ép buộc phạm vi đối tượng nhưng truy cập biến chỉ có thể đạt được thông qua các đối số truyền cho các tham số hàm. – rss181919

+0

bạn có thể lộn xộn với phạm vi từ vựng để gọi hàm qua _eval_ hoặc _with_, nhưng cách tiếp cận chức năng bằng cách sử dụng đối số truyền thường hoạt động tốt hơn trong thời gian dài và hiệu suất bằng cách thực thi ít nhất một phần đóng gói, khả năng áp dụng lại và quản lý bộ nhớ tích hợp ". nó có vẻ hơi khác một chút lúc đầu, và nó là, nhưng phong cách tiếp tục này hoạt động thực sự tốt cho các quá trình async phụ thuộc/liên quan. – dandavis

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