Hacker News new | past | comments | ask | show | jobs | submit login

Well, if so I don't think it was true until recent JS versions. And I'm not sure you're picking very good languages for your async comparison. (Python? yikes.) Long-standing async support in C# or newer support in Kotlin, or almost any language with real co-routines will fair better than JS. As for as promises go, using CPS with or without Promise wrappers seems pretty old hat.

More to the point I think, is that Node (and Deno, FWICT) lack general native or green thread support for true multi-processing without serialization to separate clusters, so you are forced to use async and timers for long-running or parallel work.




I'm not being unfair when I enumerate the most popular languages for comparison. When people crap on Javascript, they presumably prefer another language. And C#/Kotlin aren't exactly the top picks.

Kotlin has BYOB coroutines which are hard to work with. People don't use them. Going with the C# approach where async behavior looks sync was a bad move. I predict Kotlin's coroutines will never be a centerpiece abstraction just like how people don't really use Go's channels (people in practice just go back to Mutexes).

I mean, try it. Write the equivalent to this in Kotlin:

    // get background work started now
    const background = promise()
    
    // crawl some urls concurrently as well, just 4 at a time
    const crawl = Promise.map(urls, crawl, { concurrency: 4 })

    // while that's going on, we have some work that
    // we must get done.
    for (const task of tasks) {
      await worker(task)
    }

    // worker's done, now we can wait on 
    // the crawler and background work.
    const [a, b] = await Promise.all([
      crawl.then(processResults),
      background
    ])
CSP never caught on because after you have more than one channel as a central bus (the toy architecture), you immediately descend into channel hell. In-channels, out-channels, channels over channels. Back to using pencil and paper and scouring your code to decode the classic buffer bloat problem.

A single-threaded event loop with a central promise abstraction is a great way to write networked code.

Btw, I use Kotlin in a large JVM project and I'm stuck with the horror of https://docs.oracle.com/javase/8/docs/api/java/util/concurre.... That's more likely what you'll be doing day to day with Kotlin, not playing with its toy coroutines.


Whats wrong with something like this

  import kotlinx.coroutines.*
  import kotlinx.coroutines.channels.Channel

  fun background(): Channel<String> {
      val ch = Channel<String>()
      GlobalScope.launch {
          delay(5000)
          ch.send("OK")
      }
      return ch
  }

  fun getWebsiteData(url: String): Channel<String> {
      val ch = Channel<String>()
      GlobalScope.launch {
          delay(4000)
          ch.send("website data")
      }
      return ch
  }

  fun work(): Channel<String> {
      val ch = Channel<String>()
      GlobalScope.launch {
          delay(1000)
          ch.send("work result")
      }
      return ch
  }

  fun main() = runBlocking {
      println("START")
      val bck = background()
      val urls = listOf("www.web1.com", "www.web2.com", "www.web3.com", "www.web4.com")
      val chs = urls.map { getWebsiteData(it) }
      generateSequence { work() }.take(4).forEach {
          println("sync job done: " + it.receive())
      }
      chs.forEach {
          println("data fetched done: " + it.receive())
      }
      println("background done:" + bck.receive())
      println("END")
  }


Re:Kotlin, I'm not a JVM expert/fan, so I'll take your word for that. As for the lower-level coroutining, isn't the point that this will allow you/library-writers to abstract over these and provide the higher-level abstractions that you want to use?

Regarding "C# approach where async behavior looks sync", I don't follow you here. C# is very explict with async's returning Task<> where with Go's lack of "colored" fns, for example, you don't really know when you code is async or not.


Well the async/evented execution model, and omitting synchronize, complex "happens-before" semantics, and shared memory a la Java (which JavaScript and V8 lacks) is the entire point of node.js and libuv. I agree that it doesn't fit typical complex business logic with expectations of some level of isolation, but then node.js isn't a good fit for these kind of problems. Node.js is based on CommonJS, and there are/were alternative implementations of a CommonJS runtime, including process-per-request implementations like v8cgi/TeaJs, or implementations based on Rhino (Mozilla's venerable JavaScript engine written in Java) such as Ringo which can call into the JVM, and do multithreading. Complaining about this on node.js is complaining about your own decision to use node.js really. And multithreading isn't great either for these workloads; it was originally invented for coroutines in desktop apps.


> Complaining about this on node.js is complaining about your own decision to use node.js really

Yes - but there isn't much choice in the mainstream. Sure, I'd rather use .net core/Kestral, but if you want back-end JS/TS then Node is it, unless your org let's you experiment w/Deno or other.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: