简体   繁体   中英

Javascript async promises as macrotasks

In my application at some point I queue so many microtasks through promises that the UI gets blocked and becomes unresponsive.

Is there any way I can queue them as macrotasks in a similar way? Using setTimeout() works fine, the UI becomes responsive again, but the code is just horrendously ugly and gets me into callback hell.

Thanks in advance!

If you are queuing enough promises to starve the UI because promises run at a higher priority than many other types of events, then you are probably just trying to run too many asynchronous operations at once or have written the code in a way that creates far too many promises that have to be scheduled and compete with other things.

The proper way to fix this is probably to fix your code so it's not trying to create that many promises. We can only help you with that if you show us the code that is actually causing that problem.

Is there any way I can queue them as macrotasks in a similar way?

The promise implementation built-into JS does not make it configurable how promises are scheduled so they are hard-wired to use their micro tasks that are higher priority than many other things in the event queue and you cannot change that.

You could get a third party library (one that was built for promise use before JS has promises built-in) that did not have access to the microtask system and would have used something like setTimeout() or setImmediate() . But, you'd have to somehow make sure all your code was switching to this 3rd party library and not inadvertently using the built-in implementation.

Honestly that feels like a total hack and is not a solution I would pursue. The single threaded JS is a cooperative system. To keep a UI responsive, it relies on some cooperation and not hammering the main thread with high priority or long running operations in order to keep a UI responsive.

In some cases, you can move some code out to a webWorker (if this is a browser) or a WorkerThread if this is node.js and get the troublesome code out of the same event loop as the UI.

But, the best solution is probably to tame your promise-driven code so it's not running so many promise-scheduled things in a row that it interferes with the UI. We can only help with some ideas on how to do that if you show us the promise code that is actually causing the problem.

As soon as you create a promise, the promise will execute. Therefore, the promises creations need to be queued up. One of the best packages to perform these sort of operations is called async . It has 26.2K stars in Github at the time of writing.

Check out the queue example in their docs to get a better feeling for how it works:

// create a queue object with concurrency 2
var q = async.queue(function(task, callback) {
    console.log('hello ' + task.name);
    callback();
}, 2);

// assign a callback
q.drain(function() {
    console.log('all items have been processed');
});
// or await the end
await q.drain()

// assign an error callback
q.error(function(err, task) {
    console.error('task experienced an error');
});

// add some items to the queue
q.push({name: 'foo'}, function(err) {
    console.log('finished processing foo');
});
// callback is optional
q.push({name: 'bar'});

// add some items to the queue (batch-wise)
q.push([{name: 'baz'},{name: 'bay'},{name: 'bax'}], function(err) {
    console.log('finished processing item');
});

// add some items to the front of the queue
q.unshift({name: 'bar'}, function (err) {
    console.log('finished processing bar');
});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM