Как создать асинхронную функцию в Javascript?
Я имею в виду, проверить это код :
<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 "является асинхронной, и она" развивает " поток блочного кода обработчика событий. На самом деле :
$('#link').click(function () {
console.log("Enter");
asyncFunct();
console.log("Exit");
});
function asyncFunct() {
console.log("finished");
}
следуйте потоку блочного кода!
если я хочу создать свою function asyncFunct() { }
С этим поведением, как я могу сделать это с javascript / jquery? Я думаю, что есть стратегия без использования setTimeout()
12 ответов
вы не можете создать действительно настраиваемую асинхронную функцию. В конечном итоге вам придется использовать технологию, предоставленную изначально, например:
setInterval
setTimeout
requestAnimationFrame
XMLHttpRequest
WebSocket
Worker
- некоторые API HTML5, такие как API файлов, API веб-базы данных
- технологий, которые поддерживают
onload
- ... много другие!--12-->
на самом деле, для анимации jQuery использует setInterval
.
вы можете использовать таймер:
setTimeout( yourFn, 0 );
(где yourFn
является ссылкой на вашу функцию)
или Лодашь:
_.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);
}
вот функция, которая принимает другую функцию и выводит версию, которая работает асинхронно.
var async = function (func) {
return function () {
var args = arguments;
setTimeout(function () {
func.apply(this, args);
}, 0);
};
};
Он используется как простой способ сделать асинхронной функции:
var anyncFunction = async(function (callback) {
doSomething();
callback();
});
это отличается от ответа @fider, потому что сама функция имеет свою собственную структуру (без обратного вызова, она уже в функции), а также потому, что она создает новую функцию, которую можно использовать.
на этой странице проведет вас через основы создания асинхронной функции JavaScript.
выполнение асинхронных вызовов функций в JavaScript с использованием аргументов обычно включает в построении аргументации выражение в setTimeout или setInterval вручную.
Если это не решит его для вас, ознакомьтесь с документацией на .
Edit: Я не понял вопрос. В браузере я бы использовал setTimeout
. Если бы было важно, чтобы он работал в другом потоке, я бы использовал Веб-Работников.
Если вы хотите использовать параметры и регулировать максимальное количество асинхронных функций, вы можете использовать простой асинхронный рабочий, который я построил:
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);
поздно, но показать простое решение с помощью promises
после введения их в ЕС6, он обрабатывает асинхронные вызовы намного проще:
вы устанавливаете асинхронный код в новом обещании:
var asyncFunct = new Promise(function(resolve, reject) {
$('#link').animate({ width: 200 }, 2000, function() {
console.log("finished");
resolve();
});
});
Примечание Для установки resolve()
когда асинхронный вызов заканчивается.
Затем вы добавляете код, который хотите запустить после завершения асинхронного вызова внутри .then()
обетования:
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>
или JSFiddle
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, и на всякий случай вам где интересно,асинхронность.js также не предлагает действительно асинхронных функций. Вот (очень) урезанная версия основного метода библиотеки:
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
С огромным числом, чтобы занять время как демонстрация асинхронности, а затем получает двойник переданного числа.
The async
метод обеспечивает function
который вызывает нужную функцию в фоновом режиме, и в том, что предоставляется в качестве параметра async
обратные вызовы в return
в своем уникальном параметре.
Так в функция обратного вызова I alert
результат.
MDN имеет хороший пример об использовании setTimeout, сохраняющего "это".
следующим образом:
function doSomething() {
// use 'this' to handle the selected element here
}
$(".someSelector").each(function() {
setTimeout(doSomething.bind(this), 0);
});