2015-03-10 15 views
5

Tôi đang viết một số node.js để tương tác với các cảm biến qua kết nối cổng nối tiếp. Mã để đọc cảm biến không đồng bộ, một cách tự nhiên. Tuy nhiên, trong mã điều khiển của tôi, tôi cần phải đọc cảm biến, làm điều gì đó dựa trên giá trị, đọc lại, làm điều gì đó khác, v.v. Để thực hiện việc này, tôi đang sử dụng mã như sau thử nghiệm khép kín:Sử dụng chức năng máy phát điện next() dưới dạng gọi lại trong node.js

var main = new Main(); 
main.next(); 

function* Main() 
{ 
    var reading = yield readSensor(this.next.bind(this)); 
    console.log(reading); 

    var reading = yield readSensor(this.next.bind(this)); 
    console.log(reading); 
} 

function readSensor(callback) 
{ 
    // simulate asynchrounous callback from reading sensor 
    setTimeout(function sensorCallback() { callback('foo'); }, 100); 
} 

Vì vậy, mã kiểm soát tuần tự của tôi nằm trong máy phát có năng suất là readSensor() khi cần đọc. Khi đọc cảm biến được thực hiện, nó gọi lại cuộc gọi lại và kiểm soát trở lại mã chính. Tôi đang làm nó theo cách này bởi vì tôi có thể cần phải đọc từ các cảm biến khác nhau trong các đơn đặt hàng khác nhau tùy thuộc vào các bài đọc trước đó. Vì vậy, đây là phần đáng ngờ: Tôi vượt qua this.next.bind(this) dưới dạng gọi lại đến chức năng đọc không đồng bộ. Mã này dường như hoạt động khi máy phát điện được kích hoạt (--harmony_generators), nhưng tôi tự hỏi nếu có những cạm bẫy ở đây mà tôi đang thiếu. Tôi khá mới đối với JS, vì vậy đừng ngại chỉ ra điều hiển nhiên :)

+1

Tôi không nghĩ rằng bạn có thể gọi một máy phát điện ES6 như một nhà xây dựng. Có lẽ đó là lỗi v8? Hãy để tôi kiểm tra điều này. – Bergi

+0

@Bergi Tôi đã xem thông số dự thảo ES6 mới nhất, nhưng không thể quyết định xem điều này có được hỗ trợ hay không. Tôi nghĩ nó nên như vậy; nó sẽ là một cách nhẹ, tương đối rõ ràng để đối phó với vấn đề gọi lại lồng nhau. Tất nhiên, ngay cả khi bạn không thể xây dựng các máy phát như các đối tượng để chúng có một 'điều này', bạn có thể gửi cho chúng" bản ngã "của chúng với một lệnh' main.next (main); ' '. Nhưng, hiện tại, thư viện Q.async dường như làm những gì tôi theo sau. – tyapo

+0

Tôi đã nghiên cứu bản thảo ES6 chi tiết ngay bây giờ và có thể xác nhận sự nghi ngờ của tôi. Xem câu trả lời của tôi :-) – Bergi

Trả lời

2

Tôi chưa nghiên cứu máy phát điện ES6 sâu, nhưng có máy phát điện tự động chuyển .next cho một chức năng khác như gọi lại không ngồi với tôi. Nếu bất cứ điều gì, nó có thể tạo ra một tình huống mà không có readSensor và bạn không có cách nào để xử lý sự thất bại, kết thúc trong một bế tắc.

Tôi đề nghị sửa đổi hoặc gói readSensor để trả lại lời hứa và sau đó sử dụng kỹ thuật được nêu trong this article.

Điều đó sẽ cho phép bạn viết mã như thế này (Verified làm việc tại Node v0.12.0):

var Promise = require('q'); 

var main = async(function*() { 
    var reading = yield readSensor(); 
    console.log(reading); 

    reading = yield readSensor(); 
    console.log(reading); 
}); 

main(); 

function readSensor() { 
    return Promise.delay(2000).thenResolve(Math.random() * 100); 
} 



/*********************************************************** 
* From here down,           * 
* boilerplate async() function from article linked above * 
***********************************************************/ 

function async(makeGenerator){ 
    return function() { 
    var generator = makeGenerator.apply(this, arguments); 

    function handle(result){ 
     // result => { done: [Boolean], value: [Object] } 
     if (result.done) return Promise.resolve(result.value); 

     return Promise.resolve(result.value).then(function (res){ 
     return handle(generator.next(res)); 
     }, function (err){ 
     return handle(generator.throw(err)); 
     }); 
    } 

    try { 
     return handle(generator.next()); 
    } catch (ex) { 
     return Promise.reject(ex); 
    } 
    } 
} 

Như loganfsmyth lưu ý dưới đây, Q đã cung cấp một phương pháp Q.async() cung cấp các chức năng của async() chức năng này, và có thể các thư viện hứa hẹn khác cũng vậy.

+0

Hoàn toàn nằm ngoài câu hỏi chính, mục đích của '*' trong ngữ cảnh này là gì? Có một hàm được tham chiếu bởi địa chỉ bộ nhớ? Tôi chưa bao giờ thấy điều đó trong JS. – Vadorequest

+2

@Vadorequest Nó biểu thị một [chức năng máy phát điện] (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function*). – JLRishe

+0

Cảm ơn, tôi đã đọc về các tính năng của ES6 một vài tháng trước, hoàn toàn quên rằng mặc dù! Nó tương đối mới. – Vadorequest

1

Vì vậy, đây là phần đáng ngờ: Tôi chuyển this.next.bind(this) làm gọi lại cho chức năng đọc không đồng bộ. Mã có vẻ hoạt động khi máy phát được bật

Không, điều đó không hiệu quả. Máy phát điện không thể được xây dựng bằng cách sử dụng new như bạn làm. Từ the spec:

Nếu các máy phát điện đã được gọi bằng [[Gọi]], các this ràng buộc sẽ đã được khởi tạo theo cách thông thường. Nếu máy phát được gọi bằng [[Construct]] thì liên kết this không được khởi tạo và bất kỳ tham chiếu nào đến this trong phạm vi FunctionBody sẽ tạo ra ngoại lệ ReferenceError.

chức năng Generator được gọi với new (xem §9.2.3, với derived cho [[ConstructorKind]]), nhưng họ không xây dựng một ví dụ.

Khi đọc cảm biến được thực hiện, điều khiển […] trở về mã chính.

Đó thực sự là một ý tưởng thông minh.Nó đã được khám phá trước đây, xem Understanding code flow with yield/generators hoặc this article. Nhiều thư viện hỗ trợ điều này, especially combined with promises.

Tôi đề nghị bạn sử dụng một trong các thư viện này, mã hiện tại của bạn không thực sự ổn định (sẽ ngắt với hỗ trợ ES6 đầy đủ) và dường như thiếu xử lý lỗi.

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