ugrás a tartalomhoz

Node.js callback

MadBence · 2012. Jan. 16. (H), 18.22
Sziasztok!
(amennyiben egy szerkesztő úgy ítéli meg, hogy rossz fórumba küldtem a témát, nyugodtan áthelyezheti)

Hobbi szintem mostanság leginkább node.js-ben fejlesztek, és már többször belefutottam ebben a problémába. Nevezetesen, hogy hogyan "illik" kezelni a callback függvényeket.

Van az alábbi kód:
fs.readdir('./', callback);
A kód egy függvényben fut le, ami logikailag egy objektumhoz tartozik, és a callback is ehhez az objektumhoz tartozik logikailag, tehát ilyen favágó JavaScript osztály. A probléma ott van, hogy az objektum metódusaiban az ember a this-t szereti használni, csak ugye a callback meghívásakor nem az lesz a this, amit az ember ugye várna. Erre lett ugye kitalálva a that-os bűvészkedés, csak ez egyrészt ronda, másrészt szerintem egyedül akkor szabad ilyet csinálni, ha a callback ott helyben van kifejtve (névtelen függvényként), de így meg kvázi nem "az objektum metódusa", nincs benne a prototype-ban.

Tehát mi a célravezető? Legyen that, és akkor nincs probléma a "láthatósággal", viszont ott lebeg az ember szeme előtt az a perverz eset, amikor a callback függvényt úgy hívja meg az ember, hogy a that nem is létezik. Mert gyakorlatilag semmi alapja nincs annak, hogy én a that létezését készpénznek veszek. Persze erre is lehete valami workaround:
if(typeof that === 'undefined') { var that=this; }
Szerintem ez túl sok gányolás (másrészt nem bolondbiztos), valami szebbet szeretnék.

A helyben kifejtés is lehet egy alternatíva, de ez sem szimpatikus, hisz egyrészt nem lesz újrahasznosítható a kód, másrészt a rövid metódusok híve vagyok, az egymásba pakolt függvények meg nem kifejezetten lesznek rövidek.

Még kitaláltam egy olyan módszert, hogy valahogy "megtartom" a this-t:
fs.readdir('./', function(error, files){that.callback(error,files);});
Itt ugye a this szépen megmarad, de megint csak kicsit gányolásnak érzem a trükköt.

Szóval szerintetek melyik módszert érdemes használni? :)
 
1

bind

Poetro · 2012. Jan. 16. (H), 18.30
Ha amiatt aggódsz, hogy nem lesz konzisztens a kód, akkor használd a Function bind metódusát. Ezzel megadhatod, hogy mi legyen a this a callback függvényedben. Azaz:

/**
 * @constructor
 */
var MyObject = function () {}

MyObject.prototype = {
  readCallback: function () {
    // Itt a this már a MyObject egy instance-ára mutat.
  }
  read: function() {
    fs.readdir('./', this.readCallback.bind(this));
  }
}
Természetesen ez valamennyi lassulással jár, mivel a this-t újra kell értékelnie a kódnak, de ezek után a callback függvényeden belül a this az lesz, amire számítasz (mindenesetre az, amit beállítottál).
Vagy, hogyha gyakran hívod meg a read függvényt, akkor
var MyObject = function () {
  this.readCallbackInst = this.readCallback.bind(this);
}

MyObject.prototype = {
  readCallback: function () {
    // Itt a this már a MyObject egy instance-ára mutat.
  }
  read: function() {
    fs.readdir('./', this.readCallbackInst);
  }
}
és így nem kell minden esetben új függvényt generálni. Természetesen ha a read csak ritkán van meghívva, akkor felesleges a fenti gyorsítótárazás.
2

Köszi, ez pont azt csinálja,

MadBence · 2012. Jan. 16. (H), 20.28
Köszi, ez pont azt csinálja, amit én szeretnék!