Как создать асинхронную функцию в 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()
Ответы
Ответ 1
Вы не можете создать по-настоящему настраиваемую асинхронную функцию. В конечном итоге вам придется использовать технологию, предоставляемую изначально, например:
-
setInterval
-
setTimeout
-
requestAnimationFrame
-
XMLHttpRequest
-
WebSocket
-
Worker
- Некоторые API-интерфейсы HTML5, такие как API файлов, API веб-баз данных
- Технологии, поддерживающие
onload
- ... многие другие
Фактически, для анимации jQuery использует setInterval
.
Ответ 2
Вы можете использовать таймер:
setTimeout( yourFn, 0 );
(где yourFn
- ссылка на вашу функцию)
или, underscore.js:
_.defer( yourFn );
Защиты, вызывающие эту функцию, до тех пор, пока текущий стек вызовов не будет очищен, аналогично использованию setTimeout с задержкой 0. Полезно для выполнения дорогостоящие вычисления или рендеринг HTML в кусках без блокировки поток пользовательского интерфейса от обновления.
Ответ 3
здесь у вас есть простое решение (другие пишут об этом)
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 - она будет имитировать асинхронную задачу
Ответ 4
Вот функция, которая принимает другую функцию и выводит версию, выполняющую async.
var async = function (func) {
return function () {
var args = arguments;
setTimeout(function () {
func.apply(this, args);
}, 0);
};
};
Он используется как простой способ сделать асинхронную функцию:
var anyncFunction = async(function (callback) {
doSomething();
callback();
});
Это отличается от ответа @fider, потому что сама функция имеет свою собственную структуру (никакой обратный вызов не добавлен, он уже находится в функции), а также потому, что он создает новую функцию, которая может быть использована.
Ответ 5
Эта страница позволяет ознакомиться с основами создания функции async javascript.
Выполнение асинхронных вызовов функций в JavaScript с использованием аргументов обычно включает в себя построение аргумента выражения для setTimeout или setInterval вручную.
Если это не поможет вам, ознакомьтесь с документацией по функции animate
.
Ответ 6
Изменить: Я полностью не понял этот вопрос. В браузере я бы использовал setTimeout
. Если было важно, чтобы он работал в другом потоке, я бы использовал "Веб-работники" .
Ответ 7
Если вы хотите использовать параметры и регулировать максимальное количество асинхронных функций, вы можете использовать простой рабочий async, который я создал:
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 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);
Ответ 8
Я вижу здесь, что никто не говорил об этом обещании. Поэтому я рекомендую вам узнать о обещании: посмотреть эту ссылку
Ответ 9
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
.
Ответ 10
К сожалению, 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
результат.
Ответ 11
В MDN есть хороший пример об использовании setTimeout, сохраняющего "this".
Как показано ниже:
function doSomething() {
// use 'this' to handle the selected element here
}
$(".someSelector").each(function() {
setTimeout(doSomething.bind(this), 0);
});
Ответ 12
Рядом с большим ответом от @pimvdb, и на всякий случай, когда вам интересно, async.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.