JavaScriptで関数を非同期呼び出しする
よくあるパターン。
setTimeout(function(){ // 非同期でしたい処理 }, 0);
これ結構パフォーマンス悪いみたい。
node.jsの場合
process.nextTick(function(){ // 非同期でしたい処理 });
それ以外のブラウザ
MessageChannel を使うのがいいっぽい。
var ch = new MessageChannel(); ch.port1.onmessage = function(){ // 非同期でしたい処理 }; ch.port2.postMessage(0);
まとめ
だいたいこんな感じ。
uncurryThis はこの記事で知りました。
var asyncCall = function(){ var _slice = Array.prototype.slice; var _bind = Function.prototype.bind || function(thisObject){ var callee = this; var args = _slice.call(arguments, 1); return function(){ var a = _slice.call(arguments); return callee.apply(thisObject, args.concat(a)); }; }; var uncurryThis = _bind.call(_bind, Function.prototype.call); var slice = uncurryThis(_slice), bind = uncurryThis(_bind), apply = uncurryThis(Function.prototype.apply); return typeof process !== 'undefined'? function(){ var args = slice(arguments); process.nextTick(apply(bind, null, args)); }: typeof setImmediate === 'function'? function(){ var args = slice(arguments); setImmediate(apply(bind, null, args)); }: typeof MessageChannel === 'function'? function(){ var ch = new MessageChannel(), queue = []; ch.port1.onmessage = function(){ queue.shift()(); }; return function(){ var args = slice(arguments); queue.push(apply(bind, null, args)); ch.port2.postMessage(0); }; }(): function(){ var args = slice(arguments); setTimeout(apply(bind, null, args), 0); }; }();
第1引数に非同期で呼び出したい関数、第2引数にthisになるオブジェクト、第3引数以降に引数を指定する。
asyncCall(function(a, b, c){ this.valueOf(); // 0 a; // 1 b; // 2 c; // 3 }, 0, 1, 2, 3);
のように使える。