如何在 Javascript 中创建异步函数?

IT技术 javascript jquery function asynchronous
2021-01-28 23:41:07

看看这个代码

<a href="#" id="link">Link</a>
<span>Moving</span>

$('#link').click(function () {
    console.log("Enter");
    $('#link').animate({ width: 200 }, 2000, function() {
         console.log("finished");            
    });    
    console.log("Exit");    
});

正如您在控制台中看到的,“animate”函数是异步的,它“fork”了事件处理程序块代码的流程。实际上 :

$('#link').click(function () {
    console.log("Enter");
    asyncFunct();
    console.log("Exit");    
});

function asyncFunct() {
    console.log("finished");
}

按照块代码的流程!

如果我想function asyncFunct() { }用这种行为来创建我的,我怎么能用 javascript/jquery 来做呢?我认为这是不使用的策略 setTimeout()

6个回答

您无法创建真正自定义的异步函数。您最终将不得不利用本机提供的技术,例如:

  • setInterval
  • setTimeout
  • requestAnimationFrame
  • XMLHttpRequest
  • WebSocket
  • Worker
  • 一些 HTML5 API,例如 File API、Web Database API
  • 支持的技术 onload
  • ... 好多其它的

事实上,对于动画,jQuery使用 setInterval.

我昨天和朋友讨论过这个问题,所以这个答案很完美!我理解并可以识别异步函数并在 JS 中正确使用它们。我不清楚为什么我们不能实现自定义的。这就像一个黑匣子,我们知道它是如何工作的(比如使用setInterval),但我们甚至无法打开它来查看它是如何完成的。你碰巧有关于这个主题的更多信息吗?
2021-03-23 23:41:07
一些实现,特别是 Node.js,支持 setImmediate
2021-03-25 23:41:07
怎么样promises它给出一个awaitable?
2021-04-06 23:41:07
@MatheusFelipe 这些函数是 javascript 引擎实现的原生功能,您唯一可以依赖的是规范,例如 HTML5 计时器,并相信它们根据规范运行的黑盒性质。
2021-04-08 23:41:07
@MatheusFelipe youtu.be/8aGhZQkoFbQ迄今为止关于这个话题的最佳演讲......
2021-04-08 23:41:07

您可以使用计时器:

setTimeout( yourFn, 0 );

(哪里yourFn是对您的功能的引用)

或者,使用Lodash

_.defer( yourFn );

推迟调用func直到当前调用堆栈已清除。func调用时会提供任何其他参数

对于scope.setTimeout函数,如果delay省略参数,0则默认使用的值。
2021-03-25 23:41:07
@gab06 - 我想说您的画布绘图功能由于其自身的充分原因而阻塞。将其操作拆分为许多较小的操作,并使用计时器调用每个操作:您会看到这种方式的界面确实响应了您的鼠标点击等。
2021-03-29 23:41:07
这不起作用,我在画布中绘制的 javascript 函数不断使 UI 没有响应。
2021-03-31 23:41:07
setTimeout根据 HTML5 规范,最短时间为4 毫秒。给它 0 仍然需要最少的时间。但是,是的,它可以很好地用作函数延迟器。
2021-04-02 23:41:07

在这里你有简单的解决方案(其他写的) http://www.benlesh.com/2012/05/calling-javascript-function.html

在这里你有上述现成的解决方案:

function async(your_function, callback) {
    setTimeout(function() {
        your_function();
        if (callback) {callback();}
    }, 0);
}

TEST 1(可能输出 '1 x 2 3' 或 '1 2 x 3' 或 '1 2 3 x'):

console.log(1);
async(function() {console.log('x')}, null);
console.log(2);
console.log(3);

TEST 2(将始终输出 'x 1'):

async(function() {console.log('x');}, function() {console.log(1);});

此函数以超时 0 执行 - 它将模拟异步任务

是的 @nzn 和 @Joshua 我的意思是TEST 2 as: async(function() {console.log('x')}, function(){console.log(1)});- 我已经更正了
2021-03-13 23:41:07
@Joshua:似乎@fider 打算将测试 2 写为:async(function() {console.log('x')}, function(){console.log(1)});
2021-03-16 23:41:07
TEST 2 输出为 1 x in async(function() {setTimeout(()=>{console.log('x');},1000)}, function() {console.log(1);});
2021-03-20 23:41:07
TEST 1 实际上只能输出“1 2 3 x”,而 TEST 2 保证每次都输出“1 x”。TEST 2 中出现意外结果的原因是因为console.log(1)被调用并且输出 ( undefined) 作为第二个参数传递给async(). 在 TEST 1 的情况下,我认为您没有完全理解 JavaScript 的执行队列。因为每个调用都console.log()发生在同一个堆栈中,x所以保证最后记录。我会否决这个错误信息的答案,但没有足够的代表。
2021-04-07 23:41:07

这是一个函数,它接收另一个函数并输出一个异步运行的版本。

var async = function (func) {
  return function () {
    var args = arguments;
    setTimeout(function () {
      func.apply(this, args);
    }, 0);
  };
};

它被用作制作异步函数的简单方法:

var anyncFunction = async(function (callback) {
    doSomething();
    callback();
});

这与@fider 的答案不同,因为函数本身有自己的结构(没有添加回调,它已经在函数中),还因为它创建了一个可以使用的新函数。

IIRC,你也可以在没有闭包的情况下实现这一点: setTimeout(asyncFunction, 0, a);
2021-03-11 23:41:07
@ user2284570 这就是闭包的用途。 (function(a){ asyncFunction(a); })(a)
2021-03-29 23:41:07
我不明白为什么这个答案被赞成。当我把这个在我的代码,程序块,直至功能完成,这正是它应该不会做。
2021-03-31 23:41:07
setTimeout 不能在循环中使用(使用不同的参数多次调用同一个函数)
2021-04-02 23:41:07
如果我们所说的异步是指:在后台运行,与主线程并行,那么这不是真正的异步。所有这些都将延迟执行到 process.nextTick。函数中的任何代码都将在主线程上执行。如果该函数设置为计算 PI,则应用程序将冻结,无论是否超时!
2021-04-08 23:41:07

编辑:我完全误解了这个问题。在浏览器中,我会使用setTimeout. 如果它在另一个线程中运行很重要,我会使用Web Workers

? 这不会产生异步功能:O
2021-03-31 23:41:07