Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/jquery/71.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在Javascript中创建异步函数?_Javascript_Jquery_Function_Asynchronous - Fatal编程技术网

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

如何在Javascript中创建异步函数?,javascript,jquery,function,asynchronous,Javascript,Jquery,Function,Asynchronous,看看这个: 遵循块代码的流程 如果我想用这种行为创建我的函数asyncFunct(){},我如何用javascript/jquery呢?我认为有一种策略不需要使用setTimeout() ​ 编辑:我完全误解了这个问题。在浏览器中,我将使用setTimeout。如果它在另一个线程中运行很重要,我会使用。您可以使用计时器: setTimeout( yourFn, 0 ); (其中,yourFn是对您的功能的引用) 或: 延迟调用func,直到清除当前调用堆栈。调用func时,会向其提供任何附加参

看看这个:

遵循块代码的流程

如果我想用这种行为创建我的
函数asyncFunct(){}
,我如何用javascript/jquery呢?我认为有一种策略不需要使用
setTimeout()

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

您可以使用计时器:

setTimeout( yourFn, 0 );
(其中,
yourFn
是对您的功能的引用)

或:

延迟调用
func
,直到清除当前调用堆栈。调用
func
时,会向其提供任何附加参数


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

  • setInterval
  • setTimeout
  • requestAnimationFrame
  • XMLHttpRequest
  • WebSocket
  • Worker
  • 一些HTML5API,如文件API、Web数据库API
  • 支持
    onload的技术
  • 。。。许多其他
事实上,对于动画,jQuery
setInterval

将引导您完成创建异步javascript函数的基础知识


自ES2017以来,异步Javascript函数更容易编写。您还应该阅读更多相关内容。

这里您有简单的解决方案(其他请写)

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

function async(your_function, callback) {
    setTimeout(function() {
        your_function();
        if (callback) {callback();}
    }, 0);
}
测试1(可能输出'1x23'或'1x3'或'123x'):

测试2(将始终输出'x1'):

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

Function.prototype.applyAsync = function(params, cb){
      var function_context = this;
      setTimeout(function(){
          var val = function_context.apply(undefined, params); 
          if(cb) cb(val);
      }, 0);
}

// usage
var double = function(n){return 2*n;};
var display = function(){console.log(arguments); return undefined;};
double.applyAsync([3], display);
虽然与其他解决方案没有本质上的区别,但我认为我的解决方案还有一些好处:

  • 它允许为函数设置参数
  • 它将函数的输出传递给回调函数
  • 它被添加到
    函数中。prototype
    允许以更好的方式调用它
此外,与内置函数
function.prototype.apply的相似性对我来说似乎很合适

MDN对使用setTimeout保存“this”有一个定义

例如:

function doSomething() {
    // use 'this' to handle the selected element here
}

$(".someSelector").each(function() {
    setTimeout(doSomething.bind(this), 0);
});

如果要使用参数并调节异步函数的最大数量,可以使用我构建的简单异步工作程序:

var BackgroundWorker = function(maxTasks) {
    this.maxTasks = maxTasks || 100;
    this.runningTasks = 0;
    this.taskQueue = [];
};

/* runs an async task */
BackgroundWorker.prototype.runTask = function(task, delay, params) {
    var self = this;
    if(self.runningTasks >= self.maxTasks) {
        self.taskQueue.push({ task: task, delay: delay, params: params});
    } else {
        self.runningTasks += 1;
        var runnable = function(params) {
            try {
                task(params);
            } catch(err) {
                console.log(err);
            }
            self.taskCompleted();
        }
        // this approach uses current standards:
        setTimeout(runnable, delay, params);
    }
}

BackgroundWorker.prototype.taskCompleted = function() {
    this.runningTasks -= 1;

    // are any tasks waiting in queue?
    if(this.taskQueue.length > 0) {
        // it seems so! let's run it x)
        var taskInfo = this.taskQueue.splice(0, 1)[0];
        this.runTask(taskInfo.task, taskInfo.delay, taskInfo.params);
    }
}
您可以这样使用它:

var myFunction = function() {
 ...
}
var myFunctionB = function() {
 ...
}
var myParams = { name: "John" };

var bgworker = new BackgroundWorker();
bgworker.runTask(myFunction, 0, myParams);
bgworker.runTask(myFunctionB, 0, null);

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

var async = function (func) {
  return function () {
    var args = arguments;
    setTimeout(function () {
      func.apply(this, args);
    }, 0);
  };
};
它被用作生成异步函数的简单方法:

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

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

在@pimvdb的伟大答案旁边,如果你想知道的话,也不提供真正的异步函数。以下是该库主要方法的(非常)精简版本:

function asyncify(func) { // signature: func(array)
    return function (array, callback) {
        var result;
        try {
            result = func.apply(this, array);
        } catch (e) {
            return callback(e);
        }
        /* code ommited in case func returns a promise */
        callback(null, result);
    };
}

因此,该函数可以防止出错,并优雅地将其交给回调处理,但代码与任何其他JS函数一样是同步的。

不幸的是,JavaScript不提供异步功能。它只在一个线程中工作。但是大多数现代浏览器都提供了
Worker
s,这是在后台执行的第二个脚本,可以返回结果。 因此,我找到了一个解决方案,我认为异步运行一个函数很有用,它为每个异步调用创建一个工作进程

下面的代码包含要在后台调用的函数
async

Function.prototype.async = function(callback) {
    let blob = new Blob([ "self.addEventListener('message', function(e) { self.postMessage({ result: (" + this + ").apply(null, e.data) }); }, false);" ], { type: "text/javascript" });
    let worker = new Worker(window.URL.createObjectURL(blob));
    worker.addEventListener("message", function(e) {
        this(e.data.result);
    }.bind(callback), false);
    return function() {
        this.postMessage(Array.from(arguments));
    }.bind(worker);
};
这是一个用法示例:

(function(x) {
    for (let i = 0; i < 999999999; i++) {}
        return x * 2;
}).async(function(result) {
    alert(result);
})(10);
(函数(x){
对于(设i=0;i<9999999;i++){
返回x*2;
}).async(函数(结果){
警报(结果);
})(10);
这将执行一个函数,该函数使用一个巨大的数字对
进行迭代,以花时间演示异步性,然后获得传递的数字的两倍。
async
方法提供了一个
函数
,该函数在后台调用所需的函数,并且在作为
async
参数提供的函数中,该函数在其唯一参数中回调
返回

因此,在回调函数中,I
alert
会显示结果。

很晚,但为了展示一个简单的解决方案,在中引入了
承诺之后,它处理异步调用要容易得多:

您在新承诺中设置了异步代码:

var asyncFunct = new Promise(function(resolve, reject) {
    $('#link').animate({ width: 200 }, 2000, function() {
        console.log("finished");                
        resolve();
    });             
});
注意在异步调用完成时设置
resolve()

然后在promise的
中添加异步调用完成后要运行的代码。然后()

asyncFunct.then((result) => {
    console.log("Exit");    
});
以下是其中的一个片段:
$('#链接')。单击(函数(){
控制台日志(“输入”);
var asyncFunct=新承诺(函数(解析、拒绝){
$('#link')。动画({width:200},2000,function(){
控制台日志(“完成”);
解决();
}); 			
});
asyncFunct.then((结果)=>{
控制台日志(“退出”);
});
});


移动
查看jQuery源代码:).animate()方法使用回调。动画完成后,Animate将调用回调。如果您需要.animate()的相同行为,那么您需要的是回调(在一些其他操作之后由“main”函数调用)。如果您需要一个“完整”异步函数(一个在不阻塞执行流的情况下调用的函数),则情况有所不同。在这种情况下,您可以使用延迟接近0的setTimeout()。@Fabio Buda:为什么callback()应该实现某种异步?事实上,在“回调”之后,我引用了一个带有setTimeout的“完整”异步方法。我的意思是在其他代码之后调用函数的方式中,回调是伪异步的:-)?这不是我的妈妈
function asyncify(func) { // signature: func(array)
    return function (array, callback) {
        var result;
        try {
            result = func.apply(this, array);
        } catch (e) {
            return callback(e);
        }
        /* code ommited in case func returns a promise */
        callback(null, result);
    };
}
Function.prototype.async = function(callback) {
    let blob = new Blob([ "self.addEventListener('message', function(e) { self.postMessage({ result: (" + this + ").apply(null, e.data) }); }, false);" ], { type: "text/javascript" });
    let worker = new Worker(window.URL.createObjectURL(blob));
    worker.addEventListener("message", function(e) {
        this(e.data.result);
    }.bind(callback), false);
    return function() {
        this.postMessage(Array.from(arguments));
    }.bind(worker);
};
(function(x) {
    for (let i = 0; i < 999999999; i++) {}
        return x * 2;
}).async(function(result) {
    alert(result);
})(10);
var asyncFunct = new Promise(function(resolve, reject) {
    $('#link').animate({ width: 200 }, 2000, function() {
        console.log("finished");                
        resolve();
    });             
});
asyncFunct.then((result) => {
    console.log("Exit");    
});