Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
Roadie
Jun 30, 2013

smackfu posted:

A good date-time library allows you to choose whether you want a local date, a local time, or an absolute date time, since there are use cases for all of them.

Most of the cases for local dates are abstract ones like dealing with holidays, though, in which cases you're generally just mapping them to a datetime with whatever time zone you're given.

Adbot
ADBOT LOVES YOU

FSMC
Apr 27, 2003
I love to live this lie
I'm a bit confused about how javascript works and how it's all event driven rather than being in order. At first it didn't I couldn't write anything and it didn't make much sense. But then over time I could write some stuff and it didn't seem that bad. Now I'm not even more confused than before I don't know how anything I wrote works. Does everything have to be a callback of some kind or just somethings. Is it safe to write this
code:
name="fsmc"
object = getObject(name)
if(object === undefined) {
  object = {};
}
somefunction(object);
I have been writing code like that but I don't understand how it works. If things can run out of order am I just getting lucky or are simple statements be guaranteed to run in order? I tried to rewrite the code to how I thought it should be written but but kind of just gave up in the end. I don't know how I would make sure the if statement runs before the next command.
code:
function nests (name, callback) {
  getObject(name).then(object => {
    if(object === undefined) {
      object = {};
	callback(object);
    } else callback(object);
  });
}
nests("fsmc", somefunction);

Happy Thread
Jul 10, 2005

by Fluffdaddy
Plaster Town Cop
I think this advice applies to you:

JavaScript's not a particularly good language for building up intuition about what's going on "under the hood", which is absolutely crucial for understanding how to use a language so you're not constantly doing things by accident. Starting with something like C++ and moving over later works so well because C++ keeps you closer to the machine, and for most lines of code you can fully demystify for yourself what are all the baby steps the computer is taking underneath the line of code until there are no potential surprises left. In JavaScript pretty much everything can be imagined as an analogue to something from C++ so the knowledge transfers over pretty well.

To answer your question:

JavaScript's a sequential imperative language, so your lines of code will absolutely execute in order (and you can verify this by learning how to use your browser's debugger to step one line of your code at a time). You're not going to ever run into exceptions to that rule unless you're doing it on purpose, such as by introducing Promises or event handlers like in your last example. Even then, the debugger can let you set breakpoints to show you exactly in what order lines are getting called.

e: typo

Happy Thread fucked around with this message at 22:10 on Feb 9, 2019

Roadie
Jun 30, 2013
In JS, execution happens in order within a context, but whenever context changes (such as when calling or returning from a function), the engine is allowed to jump around to handle background timers, event listeners, etc.

Also, object === undefined is bad syntax, and just using name as a var without a proper var declaration will get you window.name instead and that has other complications.

JavaScript code:
function getObject(name) {
  if (name === 'cats') {
    return 'cats';
  }
}

function somefunction(obj) {
  console.log(obj);
}

(function() {
  const name = "fsmc";
  let object = getObject(name);
  if (typeof object === 'undefined') {
    object = {};
  }
  somefunction(object);
})();

Roadie fucked around with this message at 22:03 on Feb 9, 2019

roomforthetuna
Mar 22, 2005

I don't need to know anything about virii! My CUSTOM PROGRAM keeps me protected! It's not like they'll try to come in through the Internet or something!

FSMC posted:

I have been writing code like that but I don't understand how it works. If things can run out of order am I just getting lucky or are simple statements be guaranteed to run in order?
The only things that can run 'out of order' are promises and events, and they can never interrupt code that's currently running.
Javascript is hard single-threaded.
If you want it to handle events or promises in the middle of your function you have to essentially make the rest of your function be triggered by an event or promise that will resolve later than the one you want to wait for.

TIP
Mar 21, 2006

Your move, creep.



Dumb Lowtax posted:

JavaScript's a sequential imperative language, so your lines of code will absolutely execute in order (and you can verify this by learning how to use your browser's debugger to step one line of your code at a time). You're not going to ever run into exceptions to that rule unless you're doing it on purpose,

I recently ran into an exception to this, and it was pretty annoying. I was testing a fairly complicated web app, and it worked perfectly everywhere except old versions of safari, where it just totally failed.

It was obvious quickly that it was running things out of order, and trying to run functions on data that didn't exist yet. I went over my code repeatedly, trying to find my mistake but everything was in perfect order.

So I wrapped those synchronous functions in promises, and used those to lock-step through each of them in order, and it all worked.

I still don't know what the deal was, all I could think was that Apple made some ill-fated attempt to automatically multi-thread long-running functions in JavaScript. I only encountered it on old iOS safari versions.

That's also when I realized that browser updates on iOS are locked to system updates. So, if you use an iPad 2, you're forever locked to using the safari rendering engine from a million years ago. That's lame as hell.

FSMC
Apr 27, 2003
I love to live this lie

roomforthetuna posted:

The only things that can run 'out of order' are promises and events, and they can never interrupt code that's currently running.
Javascript is hard single-threaded.
If you want it to handle events or promises in the middle of your function you have to essentially make the rest of your function be triggered by an event or promise that will resolve later than the one you want to wait for.

Roadie posted:

In JS, execution happens in order within a context, but whenever context changes (such as when calling or returning from a function), the engine is allowed to jump around to handle background timers, event listeners, etc.

I thought javascript changed the order of the code and moved things about for optimisation and stuff, and that forces people to do all the call back stuff, not because they want to but have to. I guess my question is what is an "event". If an event includes functions that seems like it should effect most code. The actual example I was working on was some code had had promises everywhere which seemed to make everything inside a block run in all sorts of orders. I wanted to check some strings. Normally I would write a function to do that and that's what I did. But I really wasn't sure if that now since I was now using a function that meant the context is changing and javascript might just run the rest of the function first and then run my check string function last. If I write an AI in a single function that takes an hour to run, as long as I haven't used promises or timers will js just wait for it to finish before moving on with the rest of the code?

code:
function checkString(scheck){
 if(typeof scheck == typeof "string" && scheck.length > 0) return true;
 return false;
}
function get(roadie) {
   return new Promise((resolve, reject) => {
     if(!checkString(roadie)) {
       roadie="tuna"; 
      }
     if(roadie.includes("tuna") {
        console.log(roadie);
        resolve(roadie);
      }
      else reject(roadie);
  }
}
get("Tip")

Roadie
Jun 30, 2013

FSMC posted:

But I really wasn't sure if that now since I was now using a function that meant the context is changing and javascript might just run the rest of the function first and then run my check string function last.

No. JS is a single-threaded language, and everything in a context executes in order. It's just that jumping to or from other contexts is when the engine will also handle anything happening as an event trigger.

Also, you're using broken code again, with bad use of typeof and a broken Promise closure.

JavaScript code:
function checkString (scheck) {
  return typeof scheck === "string" && scheck.length > 0
}

function get(roadie) {
  return new Promise((resolve, reject) => {
    if (!checkString(roadie)) {
      roadie = "tuna"; 
    }
    if (roadie.includes("tuna")) {
      console.log(roadie);
      resolve(roadie);
    } else {
      reject(roadie);
    }
  })
}

get("Tip")
This (in corrected version) will always give a rejected promise.

FSMC
Apr 27, 2003
I love to live this lie

Roadie posted:

No. JS is a single-threaded language, and everything in a context executes in order. It's just that jumping to or from other contexts is when the engine will also handle anything happening as an event trigger.

Also, you're using broken code again, with bad use of typeof and a broken Promise closure.

This (in corrected version) will always give a rejected promise.
Thanks. I was thinking about doing some kind of ternary expression for checkString but thought that might be frowned upon, anyway I like your way better.
What exactly do you mean by changing contexts, if I import a module and use a function from that is that changing contexts?
Also I in terms of typeof I always check the typeof an object against another object of that type, it seems crazy and dangerous to try and memorize/lookup the actual type value and correctly type it in. Why is it bad practise to check the type of something against the type of that actual object?

roomforthetuna
Mar 22, 2005

I don't need to know anything about virii! My CUSTOM PROGRAM keeps me protected! It's not like they'll try to come in through the Internet or something!

FSMC posted:

If I write an AI in a single function that takes an hour to run, as long as I haven't used promises or timers will js just wait for it to finish before moving on with the rest of the code?
Yes (and the browser tab won't update and you can't interact with the page and consequently most browsers will eventually say "this javascript might be broken, do you want to wait for it to finish or kill it")

Edit: and "single function" isn't important, you could have it be 90 functions across multiple modules, if the function that was called doesn't return and doesn't yield to a timer or await a promise in some way the outcome is the same even if it called a bunch of other functions repeatedly or whatever.

TIP
Mar 21, 2006

Your move, creep.



FSMC posted:

If I write an AI in a single function that takes an hour to run, as long as I haven't used promises or timers will js just wait for it to finish before moving on with the rest of the code?

You could make your long running process as a web worker, and then it would get its own thread. They're actually really easy to put together, and super helpful if you need to do long calculations without blocking all your other code and the UI.

Muffiner
Sep 16, 2009

Dominoes posted:

...

If you're setting up a series of daily schedules, standalone dates (and in some cases, times) make more sense.

How do you handle a recurring daily schedule when the clocks change to or from Daylight Saving Time?

Anony Mouse
Jan 30, 2005

A name means nothing on the battlefield. After a week, no one has a name.
Lipstick Apathy

Roadie posted:

In JS, execution happens in order within a context, but whenever context changes (such as when calling or returning from a function), the engine is allowed to jump around to handle background timers, event listeners, etc.
Huh? I've never heard this explanation of execution order. Functions get called all the time, creating new execution contexts, and as far as I know that has nothing to do with execution order or "asynchronous" behavior. Isn't everything tied to the event loop?

Dominoes
Sep 20, 2007

Muffiner posted:

How do you handle a recurring daily schedule when the clocks change to or from Daylight Saving Time?
I don't understand the question.

smackfu
Jun 7, 2004

I think the suggestion was that Unix timestamp is sufficient for all problems but it would generally give the unexpected result for a repeating meeting after a DST change.

Doom Mathematic
Sep 2, 2008

Roadie posted:

In JS, execution happens in order within a context, but whenever context changes (such as when calling or returning from a function), the engine is allowed to jump around to handle background timers, event listeners, etc.

Anony Mouse posted:

Huh? I've never heard this explanation of execution order. Functions get called all the time, creating new execution contexts, and as far as I know that has nothing to do with execution order or "asynchronous" behavior. Isn't everything tied to the event loop?

Yah, that's because Roadie's initial statement isn't correct. I'm not sure what "context change" is meant to mean, but simply calling a function or returning from a function does not allow the engine to jump around to handle background timers, event listeners, etc.

At the simplest level, a JavaScript engine maintains a queue of messages, and each message essentially says "call this particular function with these parameters". In the event loop, the engine takes a message off the queue, calls the function and waits until the function has done everything it needs to do, posibly including calling many more functions, and returned. Only then, when the call stack has become empty again, does it take the next message. Nothing can interrupt this. More messages may show up on the queue while the engine is dealing with the first message, but they have to wait their turn.

Obfuscation
Jan 1, 2008
Good luck to you, I know you believe in hell
What's the easiest way to turn an existing React app into an Electron app? I tried electron-forge but it was opinionated in ways that I didn't care for and couldn't quickly figure out how to configure. I also looked at some boilerplate projects but they were all massively overcomplicated for what I actually need.

mystes
May 31, 2006

Doom Mathematic posted:

Yah, that's because Roadie's initial statement isn't correct. I'm not sure what "context change" is meant to mean, but simply calling a function or returning from a function does not allow the engine to jump around to handle background timers, event listeners, etc.

At the simplest level, a JavaScript engine maintains a queue of messages, and each message essentially says "call this particular function with these parameters". In the event loop, the engine takes a message off the queue, calls the function and waits until the function has done everything it needs to do, posibly including calling many more functions, and returned. Only then, when the call stack has become empty again, does it take the next message. Nothing can interrupt this. More messages may show up on the queue while the engine is dealing with the first message, but they have to wait their turn.
I didn't want to respond because I'm not that knowledgeable about javascript, but after Roadie's post I spent like half an hour unsuccessfully googling for evidence that browser javascript engines have some sort of secret implicit coroutines that can be switched between on function invocation/return and wondering how the heck I could have possibly never heard about this (it seems like it would be the single most significant feature of the language by far!), so I'm very relieved to hear that it's not true.

Happy Thread
Jul 10, 2005

by Fluffdaddy
Plaster Town Cop
Yeah, what the gently caress. Same here. Roadie :argh: But I quickly realized that never in all my time of single-stepping with the debugger have I ever seen it jump to another line of code somewhere else, and there's no way they would make live execution order different from the debugging execution order.

FSMC
Apr 27, 2003
I love to live this lie

roomforthetuna posted:

Yes (and the browser tab won't update and you can't interact with the page and consequently most browsers will eventually say "this javascript might be broken, do you want to wait for it to finish or kill it")

Edit: and "single function" isn't important, you could have it be 90 functions across multiple modules, if the function that was called doesn't return and doesn't yield to a timer or await a promise in some way the outcome is the same even if it called a bunch of other functions repeatedly or whatever.

OK. If I'm using a library and the function does return a promise properly. Is there a way to find of make that function act normally. I've been making my calling function async and sticking in await when using those function, but that seems to then force me to stick aync and await everywhere. Can I just make everything async/await? Also what if the module I'm calling has poorly implemented promises. Once module I was using seemed to return the promise after a message was sent on a socket rather than when the message was received or the socket closed, so it looked like once function was waiting for a response or to be closed on a socket while the other was trying to send something which resulted in errors. Is there a way to force js to ignore promises and all that jazz and only continue onto the next bit after the function properly returned. So kind of the opposite of what the promise stuff is all about.

edit: I'm using node, so user interface and clicking is a non-issue. e.g. So if I find an AI module and they have all these promises and crap but there are some errors or I can't get it to work. What's the best or simplest way to make sure when I call an AI function that takes hours to makes sure js just solely spends hours on that function before doing anything else. So even if there was a UI it would be frozen until there was a response.

FSMC fucked around with this message at 20:36 on Feb 10, 2019

Strong Sauce
Jul 2, 2003

You know I am not really your father.





FSMC posted:

OK. If I'm using a library and the function does return a promise properly. Is there a way to find of make that function act normally. I've been making my calling function async and sticking in await when using those function, but that seems to then force me to stick aync and await everywhere. Can I just make everything async/await? Also what if the module I'm calling has poorly implemented promises. Once module I was using seemed to return the promise after a message was sent on a socket rather than when the message was received or the socket closed, so it looked like once function was waiting for a response or to be closed on a socket while the other was trying to send something which resulted in errors. Is there a way to force js to ignore promises and all that jazz and only continue onto the next bit after the function properly returned. So kind of the opposite of what the promise stuff is all about.

edit: I'm using node, so user interface and clicking is a non-issue. e.g. So if I find an AI module and they have all these promises and crap but there are some errors or I can't get it to work. What's the best or simplest way to make sure when I call an AI function that takes hours to makes sure js just solely spends hours on that function before doing anything else. So even if there was a UI it would be frozen until there was a response.

you should explain what you're actually trying to do instead of explaining what you think should be happening.

promises aren't just created for the sake of creating promises. javascript handles everything asynchronously so anything that requires code to be deferred, eg. http calls or file system calls, requires you to create some kind of way for javascript to operate once the data returns either through a callback function, an event listener, or a promise. you cannot just get rid of promises.

although i'm not entirely sure what you mean by this, if a library has "poorly implemented" promises then you probably shouldn't be running the module since the code is probably not very good

"async" functions are only needed when the thing you are trying to async is not a promise. async essentially tells the engine you're going to send them a resolved promise. you can "await" a promise already without having to prepend async to a function call.

Roadie
Jun 30, 2013
Yeah, I got it way wrong, sorry. I don't know what my brain was doing to come up with that as an explanation.

Strong Sauce posted:

you should explain what you're actually trying to do instead of explaining what you think should be happening.

Yes, I'm just confusing myself more trying to figure out what FSMC is even trying to do.

Roadie fucked around with this message at 21:20 on Feb 10, 2019

Joda
Apr 24, 2010

When I'm off, I just like to really let go and have fun, y'know?

Fun Shoe
My boss said Friday that if I had ideas for how to make our model update notification system better, I'm free to look into it, after which I said "Well, I'd probably start by replacing our client poller (which, btw uses the model database to cache notifications for when it's polled) with a web sockets implementation," to which he replied "Web sockets are ancient technology." Which may very well be true, but am I wrong in thinking that for notifying clients of changes in the model, web sockets are superior to a polling solution in almost every case? And in case I'm just not in the know, are there any good alternatives presently available for pushing data from a server to a client except web sockets and polling?

Joda fucked around with this message at 22:12 on Feb 10, 2019

geeves
Sep 16, 2004

Dominoes posted:

Does anyone else think it's nuts that both builtin Date, and moment.js (Which I believe represent the large maj of date handling) don't have separate date and time types? AFAIK, the convention is to use their datetime times for dates, times, and datetimes, which is a recipe for subtle bugs. I've been using ISO strings or tuples, processing them using one of these libs are needed, then converting back.

If you're looking for something that's completely different than Date and moment.js, look into Js-Joda. It's a port of Java 8 DateTime library (which is based on Joda Time - a popular library for Java < 8). It's not yet fully internationalized and there are only 5-6 languages currently supported. Hopefully that coverage increases with time.

What's great is Js-Joda is not based on the Date object at all - it's its own implementation. It's also immutable. Also the design is a bit better.

I'm hoping TC39 or whatever takes note of this and what was done with Java and TC39 implement something like this in the future of JS (hell, even if it's C#'s implementation, ANYTHING better than what JS currently has)

  • Popular JavaScript date libraries like moment or date-utils are wrappers around the native JavaScript Date object, providing syntactic sugar. The native Date object always consist of a date, time and a timezone part. In contrast, js-joda is a standalone date and time implementation.

moment.js for all that it does (and it does a lot and is great for what it does) feels like a complete mess of ideas of how to present and manipulate datetime objects. I can think of several bugs at my company over the last year that are direct results of the moment.js api as various devs have worked with it and made changes. (I admit some of this is not reading the loving manual at times, but the bigger issues are always, always related to moment.js' lack of immutability.)

geeves fucked around with this message at 22:25 on Feb 10, 2019

smackfu
Jun 7, 2004

One of our junior devs used parseInt on an iso date to get the year. How do you even come up with that?

TIP
Mar 21, 2006

Your move, creep.



smackfu posted:

One of our junior devs used parseInt on an iso date to get the year. How do you even come up with that?

It's the top answer on stack overflow.
https://stackoverflow.com/questions/4170117/how-to-parse-the-year-from-this-date-string-in-javascript

Chenghiz
Feb 14, 2007

WHITE WHALE
HOLY GRAIL

Joda posted:

My boss said Friday that if I had ideas for how to make our model update notification system better, I'm free to look into it, after which I said "Well, I'd probably start by replacing our client poller (which, btw uses the model database to cache notifications for when it's polled) with a web sockets implementation," to which he replied "Web sockets are ancient technology." Which may very well be true, but am I wrong in thinking that for notifying clients of changes in the model, web sockets are superior to a polling solution in almost every case? And in case I'm just not in the know, are there any good alternatives presently available for pushing data from a server to a client except web sockets and polling?

There's also Server-sent Events: https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events

Compared to polling (or long polling/comet), web sockets are quite new though.

geeves
Sep 16, 2004


I hope this is an NPM module. If not I am going to create it and watch it get 5m downloads.

FSMC
Apr 27, 2003
I love to live this lie

Strong Sauce posted:

you should explain what you're actually trying to do instead of explaining what you think should be happening.

promises aren't just created for the sake of creating promises. javascript handles everything asynchronously so anything that requires code to be deferred, eg. http calls or file system calls, requires you to create some kind of way for javascript to operate once the data returns either through a callback function, an event listener, or a promise. you cannot just get rid of promises.

although i'm not entirely sure what you mean by this, if a library has "poorly implemented" promises then you probably shouldn't be running the module since the code is probably not very good

"async" functions are only needed when the thing you are trying to async is not a promise. async essentially tells the engine you're going to send them a resolved promise. you can "await" a promise already without having to prepend async to a function call.

I've managed to lose this post a few times so I'll keep this brief. The code I had problems with was something like this. I just wanted it to get the state of one device then move onto the next. But what actually happened was the the second get in the loop would start before the first one had a response. So there were errors as the first in the loop was waiting for a response and the second trying to ask a device for its state. In the end I had to get rid of loops made a messy function which called itself with the index of the next device to get.

code:
async function getState(keys) {
        keys.forEach(async key => {
          await this.get(key).then(result => console.log(result));
        });
}

Strong Sauce posted:

you can "await" a promise already without having to prepend async to a function call.

I think that's exactly what I want to do as below. But I get error when I try and use await and don't prepend async to the function call. Which kind of makes sense when I think about it and then completely no sense at all when I think a bit more. It means that all the code I write in a synchronous mindset now has half the function being async and awaits everywhere. It's kind of messy and feels like I was just wrong trying to write code as normal and maybe I should really have 10 layer deeps callbacks everywhere.

code:
async function saveData(data) {

  var currentState = await RESTCall(siteName + "/" + data.id);
  Console.log("current state" + JSON.stringify(currentState) + " data" + JSON.stringify(data));
  if (currentState.id == data.id) {
    currentState.blocks.push(data);
    data = currentState;
    RESTPut(siteName + "/" + data.id, data);
  }
  else {
    var fullData = setMainComment(data);
    Console.log("new item " + JSON.stringify(fullData) + " id " + fullData.id);
    RESTPost(siteName + "/", fullData);
  }
}

FSMC fucked around with this message at 01:03 on Feb 11, 2019

Lumpy
Apr 26, 2002

La! La! La! Laaaa!



College Slice

FSMC posted:

I've managed to lose this post a few times so I'll keep this brief. The code I had problems with was something like this. I just wanted it to get the state of one device then move onto the next. But what actually happened was the the loop the second get in the loop would start before the first one had a response. So there were errors as the first in the loop was waiting for a response and the second trying to ask a device for its state. In the end I had to get rid of loops made a messy function which called itself with the index of the next device to get.

code:
async function getState(keys) {
        keys.forEach(async key => {
          await this.get(key).then(result => console.log(result));
        });
}
I think that's exactly what I want to do as below. But I get error when I try and use await and don't prepend async to the function call. Which kind of makes sense when I think about it and then completely no sense at all when I think a bit more. It means that all the code I write in a synchronous mindset now has half the function being async and awaits everywhere. It's kind of messy and feels like I was just wrong trying to write code as normal and maybe I should really have 10 layer deeps callbacks everywhere.

code:
async function saveData(data) {

  var currentState = await RESTCall(siteName + "/" + data.id);
  Console.log("current state" + JSON.stringify(currentState) + " data" + JSON.stringify(data));
  if (currentState.id == data.id) {
    currentState.blocks.push(data);
    data = currentState;
    RESTPut(siteName + "/" + data.id, data);
  }
  else {
    var fullData = setMainComment(data);
    Console.log("new item " + JSON.stringify(fullData) + " id " + fullData.id);
    RESTPost(siteName + "/", fullData);
  }
}

This is technically not correct, but will help you get it: You have to “mark” a function that has an await inside with async so the engine knows about it ahead of time.

Roadie
Jun 30, 2013

FSMC posted:

I've managed to lose this post a few times so I'll keep this brief. The code I had problems with was something like this. I just wanted it to get the state of one device then move onto the next. But what actually happened was the the loop the second get in the loop would start before the first one had a response. So there were errors as the first in the loop was waiting for a response and the second trying to ask a device for its state. In the end I had to get rid of loops made a messy function which called itself with the index of the next device to get.

code:
async function getState(keys) {
        keys.forEach(async key => {
          await this.get(key).then(result => console.log(result));
        });
}

All you're actually doing here is creating new Promises (with the async calls) that are then wrapping other Promises. Anything in the keys.forEach could resolve in any order, because it's all async. Also, the outer async is pointless other than confusing things more, because nothing directly used in the function closure is await and it's not returning a promise.

That is to say, the code above is actually just effectively identical to:

JavaScript code:
/**
 * @param {string[]}
 * @param {Map} map
 * @return {void}
 */
function getState(keys, map) {
  keys.forEach(key => map.get(key).then(console.log))
}

Roadie fucked around with this message at 01:09 on Feb 11, 2019

roomforthetuna
Mar 22, 2005

I don't need to know anything about virii! My CUSTOM PROGRAM keeps me protected! It's not like they'll try to come in through the Internet or something!

FSMC posted:

I've managed to lose this post a few times so I'll keep this brief. The code I had problems with was something like this. I just wanted it to get the state of one device then move onto the next. But what actually happened was the the loop the second get in the loop would start before the first one had a response. So there were errors as the first in the loop was waiting for a response and the second trying to ask a device for its state. In the end I had to get rid of loops made a messy function which called itself with the index of the next device to get.

code:
async function getState(keys) {
        keys.forEach(async key => {
          await this.get(key).then(result => console.log(result));
        });
}
Aha, your problem is not actually with async/await/promises, it's forEach!
To get the result you expected, you could do
code:
async function getState(keys) {
  for (const key of keys) {
    const result = await this.get(key);
    console.log(result);
  }
}
What's happening with forEach is it calls a function for each element, and there's no 'await' in that call, so even though each function itself waits for the result, since they're async functions and the caller (forEach) isn't awaiting the outcome, the caller can carry on immediately.

(Also, there's rarely any point in mixing await and 'then' syntax in the same function.)

(Also, debug-stepping through forEach sucks balls.)

Strong Sauce
Jul 2, 2003

You know I am not really your father.





roomforthetuna posted:

Aha, your problem is not actually with async/await/promises, it's forEach!
To get the result you expected, you could do
code:
async function getState(keys) {
  for (const key of keys) {
    const result = await this.get(key);
    console.log(result);
  }
}
What's happening with forEach is it calls a function for each element, and there's no 'await' in that call, so even though each function itself waits for the result, since they're async functions and the caller (forEach) isn't awaiting the outcome, the caller can carry on immediately.

(Also, there's rarely any point in mixing await and 'then' syntax in the same function.)

(Also, debug-stepping through forEach sucks balls.)

This is the answer if you need to get sequential results (need to wait for #1 to finish before #2, #2 before #3, etc.) but if nothing is dependent on each other for resolving then consider Promise.all which will immediately try to resolve everything until all values resolve/reject before it goes onto the then statement

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all

FSMC
Apr 27, 2003
I love to live this lie

roomforthetuna posted:

Aha, your problem is not actually with async/await/promises, it's forEach!
To get the result you expected, you could do
code:
async function getState(keys) {
  for (const key of keys) {
    const result = await this.get(key);
    console.log(result);
  }
}
What's happening with forEach is it calls a function for each element, and there's no 'await' in that call, so even though each function itself waits for the result, since they're async functions and the caller (forEach) isn't awaiting the outcome, the caller can carry on immediately.

(Also, there's rarely any point in mixing await and 'then' syntax in the same function.)

(Also, debug-stepping through forEach sucks balls.)

I tried a simple for loop in the code and it works perfectly. I thought the await would prevent the next loop from running in a forEach but there is no next loop. The await just runs inside a single iteration and not between them.

I pretty sure I would have used a for loop if it wasn't for the warning from eslint against using for loops. Should I just disable that warning. It's pretty annoying and it feels like a for loop is the best option like above but I'm not sure if it's just because I don't know enough and that there is actually a much better solution out there than I can think of.
"iterators/generators require regenerator-runtime, which is too heavyweight for this guide to allow them. Separately, loops should be avoided in favor of array iterations.eslint(no-restricted-syntax)"

Strong Sauce
Jul 2, 2003

You know I am not really your father.





FSMC posted:

I tried a simple for loop in the code and it works perfectly. I thought the await would prevent the next loop from running in a forEach but there is no next loop. The await just runs inside a single iteration and not between them.

I pretty sure I would have used a for loop if it wasn't for the warning from eslint against using for loops. Should I just disable that warning. It's pretty annoying and it feels like a for loop is the best option like above but I'm not sure if it's just because I don't know enough and that there is actually a much better solution out there than I can think of.
"iterators/generators require regenerator-runtime, which is too heavyweight for this guide to allow them. Separately, loops should be avoided in favor of array iterations.eslint(no-restricted-syntax)"
there is a slight difference between the for control flow statement and foreach array iterator.

a for loop goes through the first iteration, gets held up by the await, waits for the await to resolve before moving to the next iteration of the for loop

a forEach array iterator, you pass a function. after you define a function that it immediately invokes for every single element in the array at the same time.

when you do, "[1,2,3].forEach(i=>console.log(i))" you are actually executing 3 functions all at once. since nothing is asynchronous in this case, it will output just fine. 1, 2, 3. but if each call is asynchronous, then you will get values back as soon as they resolve.

Strong Sauce fucked around with this message at 02:06 on Feb 11, 2019

Roadie
Jun 30, 2013

FSMC posted:

if it wasn't for the warning from eslint against using for loops

Using random ESLint rules before you've even got a mental model of the functionality you're using is a bad idea.

duz
Jul 11, 2005

Come on Ilhan, lets go bag us a shitpost


That's far from the only one.

roomforthetuna
Mar 22, 2005

I don't need to know anything about virii! My CUSTOM PROGRAM keeps me protected! It's not like they'll try to come in through the Internet or something!

Strong Sauce posted:

there is a slight difference between the for control flow statement and foreach array iterator.

a for loop goes through the first iteration, gets held up by the await, waits for the await to resolve before moving to the next iteration of the for loop

a forEach array iterator, you pass a function. after you define a function that it immediately invokes for every single element in the array at the same time.

when you do, "[1,2,3].forEach(i=>console.log(i))" you are actually executing 3 functions all at once. since nothing is asynchronous in this case, it will output just fine. 1, 2, 3. but if each call is asynchronous, then you will get values back as soon as they resolve.
This is misleading, nothing is ever executed "all at once" or "at the same time" in Javascript.

The forEach is effectively the same as a for loop that calls the provided function for each entry. The difference is that if that's an async function, when it hits an await or similar, it returns flow back to its caller (in the form of returning an unresolved promise under the hood). If the caller then doesn't 'await' the result of that promise, which forEach does not, then the caller moves on to whatever is next in its sequence, in this case the next subject of the forEach.

Given a regular non-async function though, a forEach executes the entries sequentially like any other for loop.

Strong Sauce
Jul 2, 2003

You know I am not really your father.





roomforthetuna posted:

This is misleading, nothing is ever executed "all at once" or "at the same time" in Javascript.
i mean yes if you want to get hung up on the word all at once then just assume i mean it's put onto the queue all at once. yes. i agree there is no uncertainty about which ordering is passed.

quote:

The forEach is effectively the same as a for loop that calls the provided function for each entry. The difference is that if that's an async function, when it hits an await or similar, it returns flow back to its caller (in the form of returning an unresolved promise under the hood). If the caller then doesn't 'await' the result of that promise, which forEach does not, then the caller moves on to whatever is next in its sequence, in this case the next subject of the forEach.

Given a regular non-async function though, a forEach executes the entries sequentially like any other for loop.
if you are saying:
code:
let print = (i) => { [(do some stuff)] }

[1,2,3].forEach(print)
is equivalent to
code:
print(1)
print(2)
print(3)
where whatever code in those functions are determined by the response time of the IO being called. then yes, i agree, and that is essentially what i said.

Strong Sauce fucked around with this message at 05:43 on Feb 11, 2019

Adbot
ADBOT LOVES YOU

Dominoes
Sep 20, 2007

geeves posted:

If you're looking for something that's completely different than Date and moment.js, look into Js-Joda. It's a port of Java 8 DateTime library (which is based on Joda Time - a popular library for Java < 8). It's not yet fully internationalized and there are only 5-6 languages currently supported. Hopefully that coverage increases with time.

What's great is Js-Joda is not based on the Date object at all - it's its own implementation. It's also immutable. Also the design is a bit better.

I'm hoping TC39 or whatever takes note of this and what was done with Java and TC39 implement something like this in the future of JS (hell, even if it's C#'s implementation, ANYTHING better than what JS currently has)

  • Popular JavaScript date libraries like moment or date-utils are wrappers around the native JavaScript Date object, providing syntactic sugar. The native Date object always consist of a date, time and a timezone part. In contrast, js-joda is a standalone date and time implementation.

moment.js for all that it does (and it does a lot and is great for what it does) feels like a complete mess of ideas of how to present and manipulate datetime objects. I can think of several bugs at my company over the last year that are direct results of the moment.js api as various devs have worked with it and made changes. (I admit some of this is not reading the loving manual at times, but the bigger issues are always, always related to moment.js' lack of immutability.)
That looks great! I didn't mention it in my post explicitly because I can't remember the details, but I recall some surprising, counter-intuitive in-place mutations occurring in moment. Before encountering moment, I ran across a Python library called Arrow; it had the highest popularity-to-messiness ratio I'd encountered, and found out later it was heavily influenced by moment. I ended up creating my own Python DT lib that thinly-wrapped the built-in one, but had some a cleaner API, and enforced TZ-awareness. I did steal Arrow's (moment's) string-formatting tokens though! Much nicer than Python's default % symbols.

Dominoes fucked around with this message at 06:29 on Feb 11, 2019

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply