查看此代码:
<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");
});
正如您在控制台中看到的那样,“动画”功能是异步的,它“分叉”了事件处理程序块代码的流程。事实上 :
$('#link').click(function () {
console.log("Enter");
asyncFunct();
console.log("Exit");
});
function asyncFunct() {
console.log("finished");
}
遵循块代码的流程!
如果我希望function asyncFunct() { }
以此行为创建自己的代码,该如何使用javascript / jquery进行创建?我认为这是不使用的策略 setTimeout()
您不能创建真正的自定义异步函数。您最终将不得不利用本机提供的技术,例如:
setInterval
setTimeout
requestAnimationFrame
XMLHttpRequest
WebSocket
Worker
- 一些HTML5 API,例如文件API,Web数据库API
- 支持的技术
onload
- ... 很多其他的
实际上,jQuery使用 动画setInterval
。
您可以使用计时器:
setTimeout( yourFn, 0 );
(在哪里yourFn
引用您的功能)
或者,使用Lodash:
_.defer( yourFn );
延迟调用,
func
直到清除当前调用堆栈。func
调用时会提供任何其他参数。
在这里,您有简单的解决方案(其他请写一下)
http://www.benlesh.com/2012/05/calling-javascript-function.html
这是您上面准备好的解决方案:
function async(your_function, callback) {
setTimeout(function() {
your_function();
if (callback) {callback();}
}, 0);
}
测试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);
测试2(将始终输出“ x 1”):
async(function() {console.log('x');}, function() {console.log(1);});
该函数在超时0时执行-将模拟异步任务
这是一个接受另一个函数并输出运行异步版本的函数。
var async = function (func) {
return function () {
var args = arguments;
setTimeout(function () {
func.apply(this, args);
}, 0);
};
};
它用作创建异步函数的简单方法:
var anyncFunction = async(function (callback) {
doSomething();
callback();
});
这与@fider的答案不同,因为该函数本身具有自己的结构(没有添加回调,它已经在函数中),并且还因为它创建了可以使用的新函数。
编辑:我完全误解了这个问题。在浏览器中,我将使用setTimeout
。如果在另一个线程中运行很重要,那么我将使用Web Workers。
本页面将引导您完成创建异步javascript函数的基础知识。
从ES2017开始,异步Javacript函数更容易编写。您还应该阅读有关Promises的更多信息。
promises
最近,但是为了展示在ES6中引入后使用的简单解决方案,它处理异步调用要容易得多:
您将异步代码设置为新的承诺:
var asyncFunct = new Promise(function(resolve, reject) {
$('#link').animate({ width: 200 }, 2000, function() {
console.log("finished");
resolve();
});
});
请注意resolve()
在异步调用结束时进行设置。
然后.then()
,在promise中添加要在异步调用完成后运行的代码:
asyncFunct.then((result) => {
console.log("Exit");
});
这是它的一个片段:
$('#link').click(function () {
console.log("Enter");
var asyncFunct = new Promise(function(resolve, reject) {
$('#link').animate({ width: 200 }, 2000, function() {
console.log("finished");
resolve();
});
});
asyncFunct.then((result) => {
console.log("Exit");
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<a href="#" id="link">Link</a>
<span>Moving</span>
如果要使用参数并调整异步函数的最大数量,可以使用我构建的一个简单的异步工作程序:
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);
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);
尽管与其他解决方案没有根本区别,但我认为我的解决方案还具有其他一些优点:
- 它允许功能参数
- 它将函数的输出传递给回调
- 它被添加到
Function.prototype
允许更好的方式来调用它
另外,与内置函数的相似性Function.prototype.apply
对我来说似乎很合适。
除了@pimvdb的出色答案之外,万一您想知道,async.js也不提供真正的异步功能。这是该库的main方法的(非常)简化版本:
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);
这执行了一个函数,该函数for
对一个巨大的数字进行迭代以花费时间来证明异步性,然后获得所传递数字的两倍。该async
方法提供了一个function
在后台调用所需函数的方法,并在其唯一参数中将其作为async
回调的return
参数提供。因此,在回调函数中,我得到alert
了结果。
MDN关于使用setTimeout保留“ this”的一个很好的例子。
如下所示:
function doSomething() {
// use 'this' to handle the selected element here
}
$(".someSelector").each(function() {
setTimeout(doSomething.bind(this), 0);
});
文章标签:asynchronous , function , javascript , jquery
版权声明:本文为原创文章,版权归 javascript 所有,欢迎分享本文,转载请保留出处!
评论已关闭!