Cara menulis fungsi asinkron untuk Node.js

114

Saya sudah mencoba meneliti tentang bagaimana tepatnya fungsi asynchronous harus ditulis. Setelah banyak membongkar banyak dokumentasi, masih belum jelas bagi saya.

Bagaimana cara menulis fungsi asynchronous untuk Node? Bagaimana cara menerapkan penanganan peristiwa kesalahan dengan benar?

Cara lain untuk mengajukan pertanyaan saya adalah ini: Bagaimana saya harus menafsirkan fungsi berikut?

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

Juga, saya menemukan pertanyaan ini di SO ("Bagaimana cara membuat fungsi asinkron non-pemblokiran di node.js?") Menarik. Saya merasa belum dijawab.

Kriem
sumber
14
Itu sebabnya saya bertanya. Tidak jelas bagi saya bagaimana fungsi-fungsi ini berbeda.
Kriem
Saya sarankan Anda melihat setTimeoutdan setIntervaldi browser favorit Anda dan bermain-main dengannya juga. Atau callback ajax (mungkin yang paling dekat dengan pengalaman node), atau event listener untuk hal-hal yang Anda kenal seperti peristiwa klik dan muat. Model asinkron sudah ada di browser, dan keduanya persis sama di node.
davin
@davin - Sepertinya saya tidak sepenuhnya memahami model asynchronous.
Kriem
@Kriem, kemarin saya menjawab sesuatu yang mungkin bisa membantu: stackoverflow.com/questions/6883648/… Ini bukan jawaban untuk pertanyaan Anda, tetapi sesuai topik. Coba dan baca pertanyaan dan jawaban di sana dan bermain-main dengan kode untuk mencoba dan memahami apa yang sedang terjadi.
davin
2
@Raynos Apa definisi "fungsi asinkron"?
Anderson Green

Jawaban:

85

Anda tampaknya membingungkan IO asinkron dengan fungsi asinkron. node.js menggunakan asynchronous non-blocking IO karena non blocking IO lebih baik. Cara terbaik untuk memahaminya adalah dengan menonton beberapa video oleh ryan dahl.

Bagaimana cara menulis fungsi asynchronous untuk Node?

Tulis saja fungsi normal, satu-satunya perbedaan adalah bahwa fungsi tersebut tidak segera dijalankan tetapi diteruskan sebagai callback.

Bagaimana cara menerapkan penanganan peristiwa kesalahan dengan benar

Umumnya API memberi Anda callback dengan err sebagai argumen pertama. Sebagai contoh

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

Merupakan pola yang umum.

Pola umum lainnya adalah on('error'). Sebagai contoh

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

Edit:

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

Fungsi di atas saat dipanggil sebagai

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

Akan mencetak 42ke konsol secara asinkron. Dalam process.nextTickkebakaran tertentu setelah callstack eventloop saat ini kosong. Tumpukan panggilan itu kosong setelahnya async_functiondan console.log(43)telah dijalankan. Jadi kami mencetak 43 diikuti oleh 42.

Anda mungkin harus melakukan beberapa pembacaan di event loop.

Raynos
sumber
Saya telah melihat video Dahl, tetapi saya tampaknya tidak memahami masalah ini. :(
Kriem
1
@Kriem melihat jawaban yang diperbarui dan membaca tentang loop acara
Raynos
1
Terima kasih untuk wawasannya. Saya sekarang lebih sadar akan apa yang kurang saya ketahui. :) Contoh terakhir Anda terbantu.
Kriem
Saya pikir pernyataan Anda tentang asynchronous IO adalah "lebih baik" terlalu umum. Dalam hal ini ya, tetapi secara keseluruhan mungkin bukan itu masalahnya.
Jake B
Dalam contoh kode pertama Anda, Anda memeriksa argumen err, tetapi tidak kembali sesudahnya. Jika terjadi kesalahan, kode akan terus berlanjut dan berpotensi menyebabkan masalah serius pada aplikasi Anda.
Gabriel McAdams
9

Hanya lewat callback saja tidak cukup. Anda harus menggunakan settimer misalnya, untuk membuat fungsi menjadi async.

Contoh: Bukan fungsi asinkron:

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");

Jika Anda akan menjalankan contoh di atas, Ini harusnya bagus, harus menunggu sampai fungsi-fungsi itu selesai berfungsi.

Fungsi pseudo multithread (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");

Yang ini akan sangat asinkron. Ini harusnya bagus akan ditulis sebelum async selesai.

Calmbird
sumber
3

Jika Anda TAHU bahwa suatu fungsi mengembalikan sebuah janji, saya sarankan menggunakan fitur async / await baru di JavaScript. Itu membuat sintaks terlihat sinkron tetapi berfungsi secara tidak sinkron. Saat Anda menambahkan asynckata kunci ke suatu fungsi, ini memungkinkan Anda untuk awaitmenjanjikan dalam lingkup itu:

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

  console.log(r); // true
}

jika suatu fungsi tidak mengembalikan sebuah janji, saya sarankan untuk membungkusnya dalam sebuah janji baru yang Anda tentukan, lalu selesaikan data yang Anda inginkan:

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: ... }
}

Intinya: manfaatkan kekuatan Janji.

ryanwaite28
sumber
Yang perlu diingat di sini adalah, body of promise masih dijalankan secara serempak.
shadow0359
2

Coba ini, ini berfungsi untuk node dan browser.

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);
});
Pradeep
sumber
18
4 suara negatif dan bahkan tidak satu komentar konstruktif ..: \
Omer
6
@Omer Begitulah kehidupan di SO.
Piece Digital
6
@NorbertoBezi Mungkin kode tersebut cukup jelas untuk Anda, tetapi tidak bagi orang yang memposting jawabannya. Itulah mengapa selalu merupakan praktik yang baik untuk menjelaskan saat downvoting.
Omer
0

Saya telah menangani terlalu banyak jam untuk tugas seperti itu di untuk node.js. Saya terutama pria front-end.

Saya menemukan ini cukup penting, karena semua metode node menangani asyncronous dengan callback, dan mengubahnya menjadi Promise lebih baik untuk menanganinya.

Saya Hanya ingin menunjukkan hasil yang mungkin, lebih ramping dan mudah dibaca. Menggunakan ECMA-6 dengan async Anda dapat menuliskannya seperti ini.

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

itu (undefined || null) adalah untuk repl (read acara cetak loop) skenario, menggunakan terdefinisi juga bekerja.

Yoarthur
sumber