1

How does one make their own asynchronous functions without access to things like Promises or Async/Await? I'm having no trouble finding examples of writing such things using these, but it requires newer versions of Javascript. I'd like to know how you'd write such things without these newer features.

When I would write a function that accepted a callback, for example

let wait5 = function (callback) {
    let expire = Date.now()+5000;
    while(Date.now() < expire){

    }
    console.log("Waited 5 seconds!")
    if(callback)
        callback();
}

wait5(function (){
    console.log("Called after waiting 5 seconds")
});
console.log("This should log before 5 seconds passes");

The above does not print log messages in the order I want, instead it blocks on wait5() until it's done waiting. Obviously The point is wait5 is meant to emulate a lengthy process, such as sending and receiving over serial or parsing a large amount of data, one that might have a long running loop and no set expected time of completion beyond 'eventually'.

So how would I make this asynchronous without Promises?

Magic Marbles
  • 403
  • 2
  • 5
  • 15
  • 1
    So without promises but with arrow funcs ? :/ – Jonas Wilms Aug 18 '17 at 18:52
  • The example is not rigorously older code, I just wrote something quick to demonstrate the behavior. – Magic Marbles Aug 18 '17 at 18:53
  • How do you spin up a new thread in node.js? Since StackSnippets are browser based, and thus single threaded, there is no way to demonstrate running this in the background with one. – Travis J Aug 18 '17 at 18:56
  • Async operations are not intended for intensive processing operations, because these operations happen synchronously. Async is basically for I/O. – Thiago Barcala Aug 18 '17 at 19:00
  • One of the situations I can think of for needing to run a function non-blockingly would be for a game - games often have very slow tasks that are best run asynchronously to prevent locking things up. AI/Path finding, rendering etc. In my case I have an app that programs a device over USB, and it would be preferable if the user could click the cancel button to halt programming mid-progress. One of these tasks involved in programming however involves queuing up messages of 256+ bytes in size for roughly 500kb, a process which takes roughly 5 to 10 seconds. – Magic Marbles Aug 18 '17 at 19:06
  • As @ThiagoBarcala points out, you seem to have a fundamental misunderstanding of terminology. You're requesting ES5 form of asynchronism, which, as is correctly pointed out, the use of `setTimeout()` as a dummy placeholder, or other asynchronous operations like AJAX calls, etc. For a long-standing blocking process, you should use a separate thread. In Node.js, there is a builtin for forking processes, in the browser, this exists through the use of the web worker API. – Patrick Roberts Aug 18 '17 at 19:07
  • @MagicMarbles Tasks performed within `Worker` thread is non-blocking as to main thread. – guest271314 Aug 18 '17 at 19:11
  • I'm using asynchronous in the sense of it's definition "two things happening at the same time". It sounds like I want to use a separate thread, though I was under the impression that Javascript didn't support multi-threading, and instead used a scheduler to alternate between tasks - which is in someway a positive about Javascript over other languages? The "one waiter handling multiple customers" versus "One waiter per customer". – Magic Marbles Aug 18 '17 at 19:14
  • 1
    Asynchronous does not mean "two things happening at the same time", that's where you're wrong. It means a task is scheduled to occur at a later time in the thread after current blocking processes have completed. In single-threaded JavaScript, there is never "two things happening at the same time". – Patrick Roberts Aug 18 '17 at 19:16
  • 1
    How could you possibly verify that two activities or events occur at the same time without a third observer? JavaScript asynchronous operations are not quantum computing. – guest271314 Aug 18 '17 at 19:16
  • I'm sorry, but I literally just googled Asynchronous and the definition was "two things happening at the same time" hence why I said I was going by that definition in terms of what I was seeking. What I wanted to know is how one goes about getting a function to run while the main process continues running (after calling it) at the same time - with the function eventually running a callback. It sure seems like Javascript is moving between two tasks when you use setTimeout with a timeout of zero, seemingly alternating between them for a period of execution time. https://pastebin.com/wwGtFgtB – Magic Marbles Aug 18 '17 at 19:23
  • @MagicMarbles _"What I wanted to know is how one goes about getting a function to run while the main process continues running (after calling it) at the same time - with the function eventually running a callback."_ Then why is that description not at text of Question? See https://stackoverflow.com/help/how-to-ask. One possible solution is to use `Worker`. Have you tried code at Answer? The effective result is what you describe at last comment. – guest271314 Aug 18 '17 at 19:25
  • 1
    You obviously misread, even google says _"(of two or more objects or events) **not** existing or happening at the same time."_ (emphasis added), and the definition, as I pointed out, _"of or requiring a form of computer control timing protocol in which a specific operation begins upon receipt of an indication (signal) that the preceding operation has been completed."_ – Patrick Roberts Aug 18 '17 at 19:26
  • @guest271314 I'm sorry but I don't think Node.js has workers – Magic Marbles Aug 18 '17 at 19:26
  • 1
    @MagicMarbles [`child_process.fork()`](https://nodejs.org/api/child_process.html#child_process_child_process_fork_modulepath_args_options) – Patrick Roberts Aug 18 '17 at 19:27
  • @MagicMarbles _"I'm sorry but I don't think Node.js has workers"_ Then what is the purpose of the Question title _"Asynchronous JS Pre-Ecma2015"_ ? – guest271314 Aug 18 '17 at 19:28
  • @PatrickRoberts well bugger me it seems I did. I am a bit dyslexic like my mother, sorry if I caused any offense. – Magic Marbles Aug 18 '17 at 19:29
  • @MagicMarbles https://www.npmjs.com/package/webworker-threads. How did you miss that link during your *oogle search for `Worker` availability at nodejs? The current Question and expected result are not clear – guest271314 Aug 18 '17 at 19:29
  • @guest271314 I don't want to make this into an argument, but webworker-threads is a package that is run by node.js, not part of node.js natively - I said I don't think it's part of Node.JS because when googling asynchronous code, Worker never comes up. It's definitely something I can look into though. – Magic Marbles Aug 18 '17 at 19:35
  • @MagicMarbles There is no "argument". Your question and expected result is simply not clear. That is a fact. Unless you can prove otherwise. Which to this point you have not done from perspective here. "asynchronous code" is a rather broad subject matter. What specific issues do you have with the specific code which you have composed? The text of the present Question does not present a clear problem statement. Again, see https://stackoverflow.com/help/how-to-ask also https://stackoverflow.com/help/mcve – guest271314 Aug 18 '17 at 19:36
  • @guest271314 I give a code example in which a function receives a callback. It prints "waited 5 seconds" after looping for 5 seconds, then runs the callback function. After in the main process wait5 is run with a following log message "this should print first". I state the issue is that they do not run in the expected order, if you run the code you see the message that should be printed first, is printed last. – Magic Marbles Aug 18 '17 at 19:49
  • @MagicMarbles If the code at Question is the actual code, the solution would be to place `console.log()` before `wait()` call. Or use `Worker` thread. The premise of the question _"Asynchronous JS Pre-Ecma2015"_ is flawed as well. Both remedied by clearly describing what you are trying to achieve. – guest271314 Aug 18 '17 at 19:53
  • The first answer given was to use setTimeout() to get it so the order of messages is logged correctly - while I said I didn't think setTimeout would achieve what I wanted, it turns out that it does in fact achieve what I wanted. The reason I haven't marked your answer as the correct one is because it came after the other correct answers. I have already acknowledged your solution also works several times, I'm not entirely sure what more you want of me. – Magic Marbles Aug 18 '17 at 19:54
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/152292/discussion-between-magic-marbles-and-guest271314). – Magic Marbles Aug 18 '17 at 19:58

3 Answers3

3

Your code is not asynchronous. A while loop is blocking, therefore the function does not end and the following console.log in the higher call stack isnt executed. You get the same behaviour with async functions too. Its not that promises turn everything into async code automatically. You may use real asynchronity:

function wait5(callback){
  setTimeout(function(){
   console.log("Waited 5 seconds!")
   if(callback) callback();
  },5000);
}

That can be also applied to looping. Instead of:

 for( var i = 0; i < 1000000; i++) sth(i);

One can do:

 (function next(i){
   sth(i);
   if(i < 1000000 - 1) setTimeout(next,0,i+1);
  })(0);
Jonas Wilms
  • 132,000
  • 20
  • 149
  • 151
  • 1
    I explicitly explain why setTimeout wasn't used in the example code. – Magic Marbles Aug 18 '17 at 18:55
  • @magic marbles may use setTimeout to slow the loop?? And make it async – Jonas Wilms Aug 18 '17 at 18:57
  • I tried this out passing in 0 as the second parameter, as you showed. I honestly didn't think about setTimeout with zero! It certainly works and modifying my wait5() function to use it gives the expected order of console.log outputs. Seems a bit hacky, I'd honestly expect something like marking a function async rather than setting a timer with zero duration. But it most certainly works. – Magic Marbles Aug 18 '17 at 19:41
  • @magic marbles well actually setTimeout 0 is a common way of pushing code onto the event queue – Jonas Wilms Aug 18 '17 at 19:45
0

You can use Worker to perform tasks outside of window, Worker.postMessage() to dispatch a message event to window which created Worker instance.

guest271314
  • 1
  • 15
  • 104
  • 177
0

Hum.. In fact you had the solution .. there is not 30 000 way to create async function callback (a callback is not necessary async, it's just a function that is called when another have been finished, if you do only sync, it's not an async callback) but setTimeout is one of it & this is how you have to do it !

This is a short list of possibility

https://stackoverflow.com/a/9516967/8395557

nodeover
  • 301
  • 1
  • 2
  • 11
  • What if we're not setting a timer, but have a very long running function that has no exact run duration - it runs until it's done and then calls back. Like parsing/serializing a large file, waiting for response on a serial port etc. – Magic Marbles Aug 18 '17 at 19:01
  • I think you do not understand correctly async, it's not async just because it's a long process. It's async in Node because it's implemented in async, you do not do anything async in you code . – nodeover Aug 18 '17 at 19:13