Node.js için eşzamansız işlevler nasıl yazılır


114

Asenkron işlevlerin tam olarak nasıl yazılması gerektiğini araştırmaya çalıştım. Çok sayıda belgeyi inceledikten sonra, hala benim için net değil.

Düğüm için eşzamansız işlevleri nasıl yazarım? Hata olayı işlemeyi doğru şekilde nasıl uygulamalıyım?

Sorumu sormanın başka bir yolu da şudur: Aşağıdaki işlevi nasıl yorumlamalıyım?

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

Ayrıca buldum SO bu soruyu ( "Nasıl node.js olmayan bir engelleme asenkron işlevi oluştururum?") İlginç. Henüz cevaplanmış gibi hissetmiyorum.


14
Bu yüzden soruyorum. Bu işlevlerin nasıl farklı olduğu bana açık değil.
Kriem

Favori tarayıcınıza bakmanızı setTimeoutve setIntervalonlarla da oynamanızı tavsiye ederim . Veya ajax geri aramaları (muhtemelen düğüm deneyimine en yakın şey) veya tıklama ve yükleme olayları gibi aşina olduğunuz şeyler için olay dinleyicileri. Eşzamansız model tarayıcıda zaten mevcuttur ve düğümde tamamen aynıdır.
davin

@davin - Asenkron modeli tam olarak anlamadığımı sanırım.
Kriem

@Kriem, dün yardımcı olabilecek bir şeyi yanıtladım: stackoverflow.com/questions/6883648/… Sorunuzun yanıtı değil, konu üzerine. Soruyu burada okuyun ve yanıtlayın ve neler olup bittiğini anlamaya çalışmak için kodla oynayın.
davin

2
@Raynos "Asenkron fonksiyonun" tanımı nedir?
Anderson Yeşil

Yanıtlar:


85

Eşzamansız GÇ'yi eşzamansız işlevlerle karıştırıyor görünüyorsunuz. node.js, engellemesiz GÇ daha iyi olduğu için eşzamansız engellemeyen GÇ kullanır. Bunu anlamanın en iyi yolu gidip Ryan Dahl'ın bazı videolarını izlemektir.

Düğüm için eşzamansız işlevleri nasıl yazarım?

Sadece normal işlevler yazın, tek fark, bunların hemen çalıştırılmaması, ancak geri arama olarak iletilmesidir.

Hata olayı işlemeyi doğru şekilde nasıl uygulamalıyım

Genellikle API'ler size ilk argüman olarak bir hata içeren bir geri arama verir. Örneğin

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

Yaygın bir kalıptır.

Başka bir yaygın model de on('error'). Örneğin

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

Düzenle:

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

Yukarıdaki işlev olarak çağrıldığında

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

42Konsola asenkron olarak yazdırılır . Özellikle process.nextTickmevcut olay döngüsü çağrı yığını boş olduktan sonra ateşlenir. Bu çağrı yığını daha sonra boş async_functionve console.log(43)çalışıyor. Yani 43 ve ardından 42 basıyoruz.

Muhtemelen olay döngüsü hakkında biraz okuma yapmalısınız.


Dahl videolarını izledim, ama korktuğum konuyu anlayamadım. :(
Kriem

1
@Kriem güncellenmiş yanıtı görün ve etkinlik döngüsü hakkında bilgi alın
Raynos

1
Görüşler için teşekkürler. Artık bilgimde eksik olduğum şeyin daha çok farkındayım. :) Bu arada son örneğiniz yardımcı oldu.
Kriem

Sanırım asenkron IO ile ilgili ifadenizin "daha iyi" olması çok genel. Bu anlamda evet, ancak genel olarak durum bu olmayabilir.
Jake B

İlk kod örneğinizde, hata argümanını kontrol ettiniz, ancak daha sonra geri dönmediniz. Bir hata durumunda, kod devam edecek ve muhtemelen uygulamanızda ciddi sorunlara neden olacaktır.
Gabriel McAdams

9

Sadece geri aramalarla geçmek yeterli değildir. Örneğin, işlevi eşzamansız yapmak için ayarlayıcı kullanmanız gerekir.

Örnekler: Eşzamansız işlevler değil:

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

Yukarıdaki örneği çalıştıracaksanız, Bu iyi olmalı, bu işlevlerin çalışması bitene kadar beklemeniz gerekecek.

Sözde çok iş parçacıklı (eşzamansız) işlevler:

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

Bu tamamen asenkron olacak. Bu, zaman uyumsuz bitmeden önce yazılacak iyi olmalı.



3

Bir işlevin bir söz verdiğini BİLİYORSANIZ, JavaScript'teki yeni async / await özelliklerini kullanmanızı öneririm. Sözdiziminin eşzamanlı görünmesini sağlar, ancak eşzamansız olarak çalışır. asyncAnahtar kelimeyi bir işleve eklediğinizde, awaitbu kapsamda vaatler yapmanızı sağlar :

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

  console.log(r); // true
}

bir işlev bir söz vermezse, onu tanımladığınız yeni bir sözle sarmalamanızı ve ardından istediğiniz verileri çözmenizi öneririm:

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

Sonuç olarak: Promises'in gücünden yararlanın.


Burada hatırlanması gereken şey, vaatlerin gövdesinin hala eşzamanlı olarak yürütülmesidir.
shadow0359

2

Bunu deneyin, hem düğüm hem de tarayıcı için çalışır.

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 olumsuz oy ve tek bir yapıcı yorum bile yok ..: \
Omer

6
@Omer Such hayat SO'da.
Piece Digital

6
@NorbertoBezi Belki kod sizin için açıklayıcıdır, ancak yanıtı gönderen için değil. Bu nedenle, olumsuz oylamayı açıklamak her zaman iyi bir uygulamadır.
Ömer

0

Node.js için böyle bir görev için çok fazla saat harcıyorum. Ben esas olarak ön uç adamım.

Bunu oldukça önemli buluyorum, çünkü tüm düğüm yöntemleri zaman uyumsuz olarak geri arama ile ilgileniyor ve onu Promise'a dönüştürmek daha iyi.

Sadece olası bir sonucu, daha yalın ve okunaklı göstermek istiyorum. ECMA-6'yı eşzamansız kullanarak bu şekilde yazabilirsiniz.

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

(undefined || null)içindir repl da tanımsız çalışma kullanarak, (okuma olay baskı döngü) senaryolar.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.