• úvod
  • témata
  • události
  • tržiště
  • diskuze
  • nástěnka
  • přihlásit
    registrace
    ztracené heslo?
    ANGEL333node.js - Evented I/O for V8 JavaScript

    Věříte, že nějaký webapp framwork postavený na node.js (Express?) bude v budoucnosti rozšířený podobně jako jsou nyní např. Django, CakePHP, Rails, Zend, atd..?

    55 hlasy od 55 respondentů

      Relativně nové server-side javascriptové API. Hlavní předností je, že je event-driven a neblokující. Již nyní obsahuje implementaci protokolů HTTP, TCP, DNS, rozhraní pro práci s procesy, soubory, atd..

      Instalace je velmi jednoduchá, jediná závislost je Python, potom node.js nainstalujete jako standardní program.

      Odkazy:


    • Oficiální web: http://nodejs.org

    • Přednáška od Ryana Dahla (autor node.js)

    • Git repozitář: http://github.com/ry/node
    • rozbalit záhlaví
      SUK
      SUK --- ---
      FEDY: knihovna s funkcema, ktera hybe vecma "nad" mi nezni zrovna jako knihovna s funkcema ale neco pomerne tesne navazany na zbytek appky. Knihovna s funkcema je neco, co presunes do jinyho projektu a dal to funguje - prave proto, ze to nepotrebuje hybat nicim jinym. Nevim ovsem, co presne zamyslis. Kazdopadne, mas nasledujici moznosti:

      1. predavat funkcim objekt a ten modifikovat
      2. pouzivat za timto ucelem callbacky
      3. IOC
      FEDY
      FEDY --- ---
      ahoj vsem,

      rad bych mel knihovnu s funkcema , kterou bych chtel pouzit ve vicero scriptech (child procesech). coz bych mohl pomoci modulu, ovsem potrebuju z modulu pristupovat k promennym a funkcim zpet nahoru z "parent" scriptu. jde to pomoci global, ale to se mi nejak nelibi. dokaze mi nekdo poradit ? (neni nutne to delat pomoci modulu a require, pokud je jina moznost)

      parent.js
      require("./module.js")();
      const promenna = "parent";
      
      test();      // test

      module.js
      module.exports = function() {
      
        this.test = function() {
          console.log('test'); 
        }
      
        console.log(promenna);     // undefined
      
      }

      Jak to udelat ?
      KOC256
      KOC256 --- ---
      AREX:
      ukládám si, zkusím díky...
      AREX
      AREX --- ---
      KOC256: Doporučuju spíš nez low-level http modul, tak vzít třeba superagent nebo axios, to ti minimálně usnadní práci s tím. A na postupne prochazeni asynchronniho pole mam takovou vlastni utilitu.

      export function asyncEach(
        input,
        mapper,
      ) {
        return input.reduce(async (promise, value) => {
          await promise
          await mapper(value).catch(err => {
            console.error(err)
          })
        }, Promise.resolve())
      }
      


      Použiješ jednoduše...

      asyncEach(urls.values, async url => {
        const response_data = await axios.get(url);
        parser.parseString(response_data)
        // etc...
      })
      
      KOC256
      KOC256 --- ---
      YORK:
      no me jde o to postupne zpracovani, coz by mi aktualne prislo nejjednodussi... Tim ze mi zbytek uz seriove funguje...

      Zbytek problemu by se pak ani nemusel resit (mixovani obsahu mezi requesty třeba...
      YORK
      YORK --- ---
      KOC256: Ten odkazovanej příklad je zrova případ, kdy chceš requesty zpracovávat postupně, ne paralelně. Tj. pošleš jeden request, až se vrátí odpověď, pošleš druhej, atd.

      Pokud chceš paralelně poslat N requestů, počkat, až na všechny dojde odpověď a pak udělat něco dalšího, potřebuješ něco jako Promise.all(), jak už tady někdo psal.

      Pokud ti stačí poslat paralelně N requestů a odpověď na každej z nich zpracovat (tj. nepotřebuješ něco dělat potom, co přijdou všechny odpovědi), stačej ti obyčejný callbacky - při vytváření každýho requestu mu předáš funkci, která se zavolá, až přijde odpověď.
      KOC256
      KOC256 --- ---
      Myslím, že vysvětlení by mohlo být skryto v tomto...

      node.js - How do I send requests in a for loop synchronously in nodejs? - Stack Overflow
      https://stackoverflow.com/...s/50668853/how-do-i-send-requests-in-a-for-loop-synchronously-in-nodejs

      jen prostě tomu pořád nerozumím... nevím jak to napasovat na ten svůj příklad...
      KOC256
      KOC256 --- ---
      AREX: No premyslim hodne PHPckovsky. Mam seznam url a na ne chci paralelne neco volat. Ten http mi dela to ze stahuje z URL XML a pak ba nem neco dela. Pro jednu URL to funguje, ale kdyz to obalim do cyklu tak se mi to splasi.

      A pokud te chapu, tak mohu 8x volat parametrizovany request, ale tomu jsem se chtel vyhnout...
      AREX
      AREX --- ---
      KOC256: Nějak se ztrácím v tom, co to má vlastně dělat. Vidím `http.get`, což je hádám http server (express?). To už je z principu asynchronní a těžko to předěláš na synchronní.

      Jestli to není express, tak bych doporučil ho použít. Zbavíš se té přímo práce se streamem.

      Co můžeš taky zkusit je místo abych pro každou url tam věšel nový listener, tak mít jenom jeden a pak z objektu requestu si načteš jakou url to požaduje a tu můžeš najít v té svojí mapě.

      Omezit concurrency samozřejmě taky můžeš, ale nemyslím si, že to něco vyřeší, pokud tam děláš side effecty, které mění něco venku co je společně.
      KOC256
      KOC256 --- ---
      No tak ještě takto. Opět asi nepochopení té asynchronity :(

      
      	var urls = new Map();
      	urls.set('cz', 'http://www.data.net/xml/cz.xml');
      	urls.set('sk', 'http://www.data.net/xml/sk.xml');
      	// ...
      
      	res.writeHead(200, {'Content-Type': 'text/html; charset=UTF-8'});
      	
      	var file = '';
      	for (let [url_key, url] of urls) {
      		file = '';
      		http.get(url, function(res0) {
      			var response_data = '';
      			res0.setEncoding('utf8');
      			res0.on('data', function(chunk) {
      				response_data += chunk;
      			});
      			res0.on('end', function() {
      				parser.parseString(response_data, function(err, result) {
      					if (err) {
      						console.log('Got error: ' + err.message);
      						res.write('Got error: ' + err.message);
      					} else {
      						console.log('Loading XML done.');
      						puppeteer.launch({
      // ... plnění proměnné file += 'nějaký kus textu';
      


      Tady mi dochází několika věcem...
      Asynchronně se ten první cyklus vyvolá pro všechny položky pole URLS... Což by úplně nevadilo kdyby... ...mi to nezačalo vyvolávat výjimky na maxListeners, kterou mám nastavenu na 100. teda pokud to chápu...
      A také to, že když níže plním v cyklech co jsem tu řešil dříve proměnou "file", tak mi to každé to spuštění v tom prvním cyklu plní tu samou proměnnou, takže pak mám v datech binec...

      Takže bych buď raději:
      - zajistil synchro - čas nehraje roli, bude to něco co bude běžet cronem na pozadí a generovat právě cache soubory
      - nebo nějak zajistit, že se ty "vllákna" spustí třeba jen 3 a nebude se mixovat ta proměnná file...

      Prosím o nějaký nákop...
      KOC256
      KOC256 --- ---
      B3DA:
      B3DA:
      Myslím, že chápu. Vyspím se na to a uvidím :)

      Díky...
      B3DA
      B3DA --- ---
      resp.
      
      try {
        // ...
        const results = await Promise.allSettled(promises)
      } catch (e) {...}
      

      at v tom nedelam bordel
      B3DA
      B3DA --- ---
      KOC256: pokud to chces poslat vse najednou, vytvor si pole tech stringu, a udelej neco jako
      const promises = arr.map(u => updatePage(u))
      Promise.allSettled(promises)
        .then(results => {
          // foreach results = r => r.status === 'fullfiled' ? r.value : r.reason ...
        }).catch(...)
      

      muzes pouzit i Promise.all(), ale pokud ti spadne jeden request, rejectne se i zbytek..
      KOC256
      KOC256 --- ---
      YORK:
      No je to v podstatě moje druhá appka, takže ani moc nevím co a jak refaktorizovat. Jsou to nějaké kusy kódů z tutoriálů a googlení.

      no musel jsem ty foreache přepsat na for, protože jinak při prostém přidání async přes ty dvě functions, to stejně padalo zase na nějakou chybu s tím volaním stránky. Předpokládám, že nějaká vlastnost těch async...

      Nyní tedy takto:
      // NE Object.keys(result.GP.c).forEach(async function(k) {
      for (var k in Object.keys(result.GP.c)) {

      Aha, tak ted zjistuji, ze to tu mam dve hodiny rozepsane... :D
      A dosel jsem k tomu samemu jako B3DA.

      Jen je pravda, ze mi to vsechno jede seriove, takze jak tu zaznelo poooomaaaaaluuuu.

      Jak to teda napsat, aby ten cyklus probihal asynchronne? Asi staci naznacit konstrukcne... :o)
      YORK
      YORK --- ---
      AREX: Awaity v cyklu udělat jdou, akorát pak přijdeš o výhodu asynchronního kódu. Počká to nejdří na první, pak na druhej, pak na třetí, atd. Promise.all() se od toho liší v tom, že může všechno probíhat současně a čekáš na to, až doběhnou všechny.

      (Rozumnej linter samozřejmě await v cyklu označí jako chybu, protože to prakticky nikdy nechceš udělat. Ale technicky to jde.)
      B3DA
      B3DA --- ---
      v tomhle pripade mozna spis
      Promise.allSettled()

      nebo treba neco jako
      
      for (const key of Object.keys(result.GP.c)) {
        const foo = await updatePage(result.GP.c[k].code[kk])
      }
      
      AREX
      AREX --- ---
      YORK: Dělat callback do `forEach` jako async nebude nikdy fungovat, protože na to nebude nic čekat. Obecně smyčky a async je bolavé téma. Takový ošklivý hack je `await Promise.all(result.GP.c.map(async ...)`

      Ale ta dvakrát vnořená smyčka v tom udělá ještě větší bordel :) Takový jiný trick je v podstatě chainovat jeden Promise a ten pak počkat.

      KOC256: Asi bych ti doporučil nejprve v rámci těch smyček se sestavit flat array, to můžeš v pohodě udělat synchronně a pak použít ten trik co jsem psal výše s Promise.all.
      YORK
      YORK --- ---
      KOC256: Aha, v tom případě není problém v tom, že bys přes await volal funkci, která není async, ale že používáš await ve funkci, která není async. Řekl bych, že jak máš

      "Object.keys(result.GP.c).forEach(function(k) {"

      tak to 'funcion(k)' musí bejt async.


      Osobně bych ten kód refactoroval, všechny inline funkce bych pojmenoval a vyhodil ven, aby bylo dobře vidět, že každou async funkci voláš přes await a že každá funkce, ve který používáš await, je async.
      KOC256
      KOC256 --- ---
      YORK:
      kdyz spodni kod hodim do toho vrchniho pod radek console.log('Loading XML done.');
      tak to zacne hajlovat, ze se mu nelibi Await postupne u:
      await page.goto('https://www.neco.com/' + result.GP.c[k].code[kk], {waitUntil: 'networkidle2'});
      if (await page.$('#CB_dMessage') != null) {
      } else if (await page.$('#CB_aMessage') != null) {

      Kdyz je dam pryc tak to zhuci, protoze samozrejme ty page.$... necekaji na nacteni stranky a tedy tam nic nenajdou...
      KOC256
      KOC256 --- ---
      YORK:
      No to jsem samozrejme zkousel, ale proste porad se tomu neco nelibilo...

      Da se prvni blok zaobalit do nejakeho stavu, kde bude vracet jen promenou "result", kterou si prave v tom spodnim kodu nejak nactu?

      Jinak pokud to chapu, tak musim bud vrchni kod dostat doprostred toho spodniho, nebo ten spodni do prostred toho vrchniho. COz mi pak prijde cele to strasne zneprehlednujici... :(
      YORK
      YORK --- ---
      KOC256: Zkuz smazat 'await' z řádku, kde ti to píše syntax error.
      Kliknutím sem můžete změnit nastavení reklam