Cách viết các hàm không đồng bộ cho Node.js


114

Tôi đã cố gắng nghiên cứu về cách chính xác các hàm không đồng bộ nên được viết. Sau khi cày rất nhiều tài liệu, tôi vẫn chưa rõ lắm.

Làm cách nào để viết các hàm không đồng bộ cho Node? Làm cách nào để triển khai xử lý sự kiện lỗi một cách chính xác?

Một cách khác để đặt câu hỏi của tôi là: Tôi nên diễn giải hàm sau như thế nào?

var async_function = function(val, callback){
    process.nextTick(function(){
        callback(val);
    });
};

Ngoài ra, tôi thấy câu hỏi này trên SO ("Làm cách nào để tạo một hàm không đồng bộ không chặn trong node.js?") Thú vị. Tôi không cảm thấy như nó đã được trả lời được nêu ra.


14
Đó là lý do tại sao tôi đang hỏi. Tôi không rõ các chức năng này khác nhau như thế nào.
Kriem

Tôi khuyên bạn nên xem setTimeoutsetIntervaltrong trình duyệt yêu thích của mình cũng như chơi với chúng. Hoặc gọi lại ajax (có thể là thứ gần nhất với trải nghiệm nút) hoặc trình xử lý sự kiện cho những thứ bạn quen thuộc như nhấp và tải sự kiện. Mô hình không đồng bộ đã tồn tại trong trình duyệt và chúng hoàn toàn giống nhau trong nút.
davin

@davin - Đoán là tôi không hiểu đầy đủ về mô hình không đồng bộ.
Kriem

@Kriem, hôm qua tôi đã trả lời điều gì đó có thể hữu ích: stackoverflow.com/questions/6883648/… Đây không phải là câu trả lời cho câu hỏi của bạn, nhưng là chủ đề. Hãy thử và đọc câu hỏi và câu trả lời ở đó và nghịch mã để thử và hiểu điều gì đang xảy ra.
davin

2
@Raynos Định nghĩa của "hàm không đồng bộ" là gì?
Anderson Green

Câu trả lời:


85

Có vẻ như bạn đang nhầm lẫn giữa IO không đồng bộ với các hàm không đồng bộ. node.js sử dụng IO không chặn không đồng bộ vì IO không chặn tốt hơn. Cách tốt nhất để hiểu nó là xem một số video của ryan dahl.

Làm cách nào để viết các hàm không đồng bộ cho Node?

Chỉ cần viết các hàm bình thường, điểm khác biệt duy nhất là chúng không được thực thi ngay lập tức mà được chuyển xung quanh dưới dạng lệnh gọi lại.

Làm cách nào để triển khai xử lý sự kiện lỗi một cách chính xác

Nói chung API cung cấp cho bạn một lệnh gọi lại với lỗi là đối số đầu tiên. Ví dụ

database.query('something', function(err, result) {
  if (err) handle(err);
  doSomething(result);
});

Là một khuôn mẫu chung.

Một mô hình phổ biến khác là on('error'). Ví dụ

process.on('uncaughtException', function (err) {
  console.log('Caught exception: ' + err);
});

Biên tập:

var async_function = function(val, callback){
    process.nextTick(function(){
        callback(val);
    });
};

Hàm trên khi được gọi là

async_function(42, function(val) {
  console.log(val)
});
console.log(43);

Sẽ in 42ra bảng điều khiển không đồng bộ. Đặc biệt process.nextTickkích hoạt sau khi ngăn gọi eventloop hiện tại trống. Ngăn xếp cuộc gọi đó trống sau async_functionconsole.log(43)đã chạy. Vì vậy, chúng tôi in 43 tiếp theo là 42.

Bạn có thể nên đọc một số vòng lặp sự kiện.


Tôi đã xem các vids của Dahl, nhưng dường như tôi không hiểu được vấn đề mà tôi sợ. :(
Kriem

1
@Kriem xem câu trả lời cập nhật và đọc về vòng lặp sự kiện
Raynos

1
Cảm ơn vì những hiểu biết sâu sắc. Bây giờ tôi nhận thức rõ hơn về những gì tôi thiếu kiến ​​thức. :) Ví dụ cuối cùng của bạn đã giúp đỡ bằng cách này.
Kriem

Tôi nghĩ rằng tuyên bố của bạn về IO không đồng bộ là "tốt hơn" là quá chung chung. Theo nghĩa này, có, nhưng nhìn chung có thể không đúng như vậy.
Jake B

Trong ví dụ mã đầu tiên của bạn, bạn kiểm tra đối số sai, nhưng không trở lại sau đó. Trong trường hợp có lỗi, mã sẽ tiếp tục và có khả năng gây ra sự cố nghiêm trọng trong ứng dụng của bạn.
Gabriel McAdams

9

Chỉ lướt qua các cuộc gọi lại là không đủ. Bạn phải sử dụng settimer chẳng hạn, để làm cho hàm không đồng bộ.

Ví dụ: Không phải hàm không đồng bộ:

function a() {
  var a = 0;    
  for(i=0; i<10000000; i++) {
    a++;
  };
  b();
};

function b() {
  var a = 0;    
  for(i=0; i<10000000; i++) {
    a++;
  };    
  c();
};

function c() {
  for(i=0; i<10000000; i++) {
  };
  console.log("async finished!");
};

a();
console.log("This should be good");

Nếu bạn chạy ví dụ trên, Điều này sẽ tốt, sẽ phải đợi cho đến khi các chức năng đó kết thúc để hoạt động.

Chức năng đa luồng giả (async):

function a() {
  setTimeout ( function() {
    var a = 0;  
    for(i=0; i<10000000; i++) {
      a++;
    };
    b();
  }, 0);
};

function b() {
  setTimeout ( function() {
    var a = 0;  
    for(i=0; i<10000000; i++) {
      a++;
    };  
    c();
  }, 0);
};

function c() {
  setTimeout ( function() {
    for(i=0; i<10000000; i++) {
    };
    console.log("async finished!");
  }, 0);
};

a();
console.log("This should be good");

Cái này sẽ không đồng bộ. Điều này nên tốt sẽ được ghi trước khi quá trình async kết thúc.



3

Nếu bạn BIẾT rằng một hàm trả về một lời hứa, tôi khuyên bạn nên sử dụng các tính năng async / await mới trong JavaScript. Nó làm cho cú pháp trông đồng bộ nhưng hoạt động không đồng bộ. Khi bạn thêm asynctừ khóa vào một hàm, nó cho phép bạn awaithứa trong phạm vi đó:

async function ace() {
  var r = await new Promise((resolve, reject) => {
    resolve(true)
  });

  console.log(r); // true
}

nếu một hàm không trả về một lời hứa, tôi khuyên bạn nên gói nó trong một lời hứa mới mà bạn xác định, sau đó giải quyết dữ liệu mà bạn muốn:

function ajax_call(url, method) {
  return new Promise((resolve, reject) => {
    fetch(url, { method })
    .then(resp => resp.json())
    .then(json => { resolve(json); })
  });
}

async function your_function() {
  var json = await ajax_call('www.api-example.com/some_data', 'GET');
  console.log(json); // { status: 200, data: ... }
}

Điểm mấu chốt: tận dụng sức mạnh của Lời hứa.


Điều cần nhớ ở đây là, nội dung của lời hứa vẫn được thực hiện đồng bộ.
shadow0359,

2

Hãy thử điều này, nó hoạt động cho cả nút và trình duyệt.

isNode = (typeof exports !== 'undefined') &&
(typeof module !== 'undefined') &&
(typeof module.exports !== 'undefined') &&
(typeof navigator === 'undefined' || typeof navigator.appName === 'undefined') ? true : false,
asyncIt = (isNode ? function (func) {
  process.nextTick(function () {
    func();
  });
} : function (func) {
  setTimeout(func, 5);
});

18
4 phiếu phản đối và thậm chí không một nhận xét mang tính xây dựng ..: \
Omer

6
@Omer Đó là cuộc sống trên SO.
Piece Digital

6
@NorbertoBezi Có thể mã tự giải thích cho bạn, nhưng không phải cho người đã đăng câu trả lời. Đó là lý do tại sao luôn luôn là một thực tiễn tốt để giải thích khi phản đối.
Omer

0

Tôi đã xử lý quá nhiều giờ cho nhiệm vụ như vậy trong node.js. Tôi chủ yếu là anh chàng front-end.

Tôi thấy điều này khá quan trọng, bởi vì tất cả các phương thức nút không đồng bộ đều xử lý lệnh gọi lại và chuyển nó thành Promise sẽ tốt hơn để xử lý nó.

Tôi chỉ muốn đưa ra một kết quả khả thi, dễ hiểu hơn và dễ đọc hơn. Sử dụng ECMA-6 với async, bạn có thể viết nó như thế này.

 async function getNameFiles (dirname) {
  return new Promise((resolve, reject) => {
    fs.readdir(dirname, (err, filenames) => {
      err !== (undefined || null) ? reject(err) : resolve(filenames)
    })
  })
}

những (undefined || null)là cho repl (đọc sự kiện in loop) kịch bản, sử dụng làm việc không xác định cũng có.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.