最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Does setTimeout() run on a separate thread? - Stack Overflow

programmeradmin8浏览0评论

Curious to see whether setTimeout() will be fired up asynchronously, I tried the following test script:

function timedText() {
  var x = document.getElementById("txt");
  setTimeout(function() {
    x.value = "1 second"
  }, 1000);
  setTimeout(function() {
    x.value = "2 seconds"
  }, 2000);
  setTimeout(function() {
    x.value = "3 seconds"
  }, 3000);

  while (true) {}
}
<p>Click on the button below. The input field will tell you when two, four, and six seconds have passed.</p>

<button onclick="timedText()">Display timed text</button>
<input type="text" id="txt">

Curious to see whether setTimeout() will be fired up asynchronously, I tried the following test script:

function timedText() {
  var x = document.getElementById("txt");
  setTimeout(function() {
    x.value = "1 second"
  }, 1000);
  setTimeout(function() {
    x.value = "2 seconds"
  }, 2000);
  setTimeout(function() {
    x.value = "3 seconds"
  }, 3000);

  while (true) {}
}
<p>Click on the button below. The input field will tell you when two, four, and six seconds have passed.</p>

<button onclick="timedText()">Display timed text</button>
<input type="text" id="txt">

Sure enough, clicking the button causes the browser to hang.

This tells me that setTimeout() does not run on a separate thread.

But on a recent interview, the interviewer suggested otherwise... Does that mean that setTimeout() is browser/implementation dependent?

Share Improve this question edited Aug 22, 2018 at 6:35 Very Objective asked Aug 22, 2018 at 6:22 Very ObjectiveVery Objective 6267 silver badges16 bronze badges 6
  • Whats the while(true)-loop or the int=0 for? – Ahorn Commented Aug 22, 2018 at 6:29
  • @WhiteMaple var int=0 is a leftover typo from when I tried a long loop that eventually exits (sort of my own timeout instead of the browser's timeout). You can ignore it as it doesn't really change the behavior of this sample test. – Very Objective Commented Aug 22, 2018 at 6:32
  • 2 No, it means your interviewer is wrong. – Potato Salad Commented Aug 22, 2018 at 6:34
  • That depends what you call setTimeout... The actual function is called synchronously (and is only "register callback to fire a t "). The callback will get called synchronously when currentTime > t, and when the js context is free. But the actual currentTime gets incremented by the machine, and is not tied by js context. So if you consider this timer increment as part of the whole setTimeout, then your interviewer had a point. – Kaiido Commented Aug 22, 2018 at 6:39
  • @Kaiido well then every programing language would be multi-threaded as long as the operating system which does the io handling is multi-threaded. This argument is a little too artificial. – t.niese Commented Aug 22, 2018 at 7:17
 |  Show 1 more ment

5 Answers 5

Reset to default 14

JavaScript is not multi threaded. Well there are WebWorkers that run in a different thread, but that's not really multi threading, more like multiple processes, that municate with each other.

As of that the while (true) {} will block the js context, because it is an endless loop.

The setTimeout will register a function for later execution. But at no time code will run in parallel for the same context.

A while (true) itself does not necessarily create a blocking loop:

async function sleep(time) {
  return new Promise((resolve, _) => setTimeout(resolve, time))
}

async function test(val) {
  while (true) {
    console.log('in while loop ' + val)
    await sleep(1000)
  }
}

test('foo')
test('bar')

So you can say with await/async you can create some kind of cooperative multitasking like setup, but still no multi threading

There is no thread in javascript. setTimeout push just the delegate function insto a stack that will pop for the next pass. You can read that JavaScript and Threads

This tells me that setTimeout() does not run on a separate thread.

Yes. There is only one thread in JS.

But on a recent interview, the interviewer suggested otherwise... Does that mean that setTimeout() is browser/implementation dependent?

As far as i know only engine changed from browser to browser. Internal mechanism stands the same - event-loop processor.

When you call setTimeout() typically control is passing back into the host environment (the browser or native node.js code for example). What is happening then is that your callback is being registered in a list of timers to execute in the future. setTimeout() will the return back to your code which will continue executing.

When your script finally pletes, control again will return to the host environment which has an event loop, this loop keeps spinning until it's finally time to call your registered callback.

You can actually approximate something like this in JavaScript itself by implementing an event loop just for fun:

class EventLoop {

    constructor() {
        this.entries = [];  // a list of all registered callbacks
        this.turns = 0;     // keep track of how many turns of the loop we make
    }

    // Adds a new callback to the list

    schedule(callback, condition) {
        this.entries.push([condition, callback]);
    }

    // To removes a callback when it's been called

    remove(entry) {
        this.entries.splice(this.entries.indexOf(entry), 1);
    }

    // Run the loop until all registered callbacks were called
    // Returns the number of turns it made in the while loop

    run(timeout) {

        this.turns = 0;

        while (this.entries.length) {
            for (const entry of this.entries) {
                const [condition, callback] = entry;
                if (condition()) {
                    callback();
                    this.remove(entry);
                }
            }

            this.turns++;
        }

        return this.turns;
    }

}

We can use this EventLoop to implement something like a setTimeout():

// Define a handy log function

const log = ((startTime) => (text) => {

    console.log(`t+${(Date.now() - startTime).toFixed(3)}ms: ${text}`);

})(Date.now());

// Create an event loop

const loop = new EventLoop();

// Define a setTimeout using the event loop

const defer = (fn, timeout) => {

    const start = Date.now();
    const end = start + timeout;

    loop.schedule(fn, () => Date.now() >= end);
};

// Schedule some nested events

defer(() => {

    log('I run second');

    defer(() => {

        log('I run third');

        defer(() => {

            log('I run fourth');

        }, 200);

    }, 200);

}, 200);

// Log syncronously

log('I run first');

// Start the event loop turning (blocks until all events are plete)

const turns = loop.run();

log(`Loop exited after ${turns} turns`);

// This will log after event loop has finished running

log('I run last');

If you run this with node.js you'll get the following output:

t+0.000ms: I run first t+200.000ms: I run second t+400.000ms: I run third t+600.000ms: I run fourth t+600.000ms: Loop exited after 6441157 turns t+600.000ms: I run last

We just created an asynchronous timeout in pure JavaScript with a single thread. Now in reality you wouldn't do this in JavaScript, the event loop would be implemented in native code and hosted in the host environment. An example of such an event loop is libuv used by Node.js. Libuv can do things more efficiently than our toy JS example, it can put the current thread to sleep (technically it doesn't do this, it polls for IO but same concept) so it's not wasting CPU cycles.

Those asynchronous functions are handled by the browser. not the JavaScript engine. there are no threads in JavaScript.

发布评论

评论列表(0)

  1. 暂无评论