これを確認してください code :
<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
onload
をサポートするテクノロジー実際、アニメーションjQueryでは sessetInterval
。
タイマーを使用できます:
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 を使用します。
遅いですが、 ES6 で紹介した後にpromises
を使用して簡単な解決策を示すために、非同期呼び出しをはるかに簡単に処理します。
新しいpromiseに非同期コードを設定します。
var asyncFunct = new Promise(function(resolve, reject) {
$('#link').animate({ width: 200 }, 2000, function() {
console.log("finished");
resolve();
});
});
非同期呼び出しが終了したときにresolve()
を設定することに注意してください。
次に、promiseの.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
パラメーターを使用し、非同期関数の最大数を調整する場合は、私が作成した単純な非同期ワーカーを使用できます。
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は非同期機能を提供していません。単一の1つのスレッドでのみ機能します。しかし、最新のブラウザのほとんどはWorker
sを提供します。これは、バックグラウンドで実行され、結果を返すことができる2番目のスクリプトです。だから、非同期呼び出しごとにワーカーを作成する関数を非同期的に実行すると便利だと思うソリューションに到達しました。
以下のコードには関数が含まれています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
を巨大な数で反復して非同期性のデモンストレーションとして時間をかける関数を実行し、渡された数の2倍を取得します。 async
メソッドは、必要な関数をバックグラウンドで呼び出すfunction
を提供し、async
のパラメーターとして提供されるメソッドでは、その固有のパラメーターでreturn
をコールバックします。したがって、コールバック関数では、結果をalert
にします。
MDNには、「this」を保持するsetTimeoutの使用に関する 良い例 があります。
次のように:
function doSomething() {
// use 'this' to handle the selected element here
}
$(".someSelector").each(function() {
setTimeout(doSomething.bind(this), 0);
});