ブラウザをフリーズさせない同期 AJAX クエリを実行する方法はありますか? 私の意見では、ほとんどの場合、同期リクエストの方が作業がはるかに簡単ですが、コードの他の部分の実行がブロックされるという事実は、本当に致命的です。マイナスの副作用なしで同期 AJAX を取得する方法はありますか? (そして、はい、「同期 AJAX」という用語は矛盾していることに気付きました。)
5 に答える
いいえ。同期は、定義上、ブロッキングです。プロセスが完了するまで、何も進むことはできません。これには、Web ブラウザーの残りの UI が含まれます。
非同期であることが想定されているため、非同期で動作するようにコードを設計するのが最善の方法です。
async
今後の ECMAScript 2016 (ES7) 標準には、 and と呼ばれる、探していると思われるものと非常によく似た機能を実行するように設計された新しい言語キーワードのセットがありますawait
。
これらのキーワードでは、「ノンブロッキング同期 AJAX」は許可されませんが、同期のように見える方法で非同期コードを記述できます。簡単な例を次に示します。
// Let's say you have an asynchronous function that you want to call in a synchronous
// style...
function delayedEval(delay, func) {
// First, ensure that the function returns a Promise object. If it doesn't, wrap it with
// another function that does.
return new Promise((resolve, reject) => {
setTimeout(() => resolve(func()), delay)
})
// For more on Promises, see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
}
// Then, declare a function as asynchronous. This causes it to return a Promise that
// resolves to its return value, instead of returning its return value directly.
async function delayedHello() {
// Inside an async function, you can call other async functions like this, which looks
// very much like a synchronous call (even though it isn't).
let message = await delayedEval(1500, () => "Hello, world!")
console.log(message)
}
// This returns (a Promise) immediately, but doesn't print "Hello, world!" until 1.5
// seconds later. (At which point it resolves the Promise.)
delayedHello()
基本的に、「負の副作用のない同期 AJAX」の代わりに、すべての負の副作用のない非同期async
AJAXをawait
取得します。(コールバックを処理するための多くのロジックを含む厄介なコード。)
async
ES7標準の「非同期関数」候補の推奨事項のawait
一部です。
ここの他の回答で概説されている理由により、ブラウザーで他のイベントをブロックせずに同期 AJAX 呼び出しを実行する方法はありません。
ただし、非同期メソッド呼び出しを避けたい主な理由がコードの複雑さである場合は、Javascript クロスコンパイラstreamline.jsに興味があるかもしれません。これにより、非同期メソッド呼び出しを同期であるかのように記述して、同じ結果を得ることができます。非同期で呼び出しを書いたかのように。
プロジェクトの GitHub ページから:
streamline.js は、非同期 Javascript プログラミングを簡素化するための言語ツールです。
次のような毛むくじゃらのコードを書く代わりに:
function archiveOrders(date, cb) { db.connect(function(err, conn) { if (err) return cb(err); conn.query("select * from orders where date < ?", [date], function(err, orders) { if (err) return cb(err); helper.each(orders, function(order, next) { conn.execute("insert into archivedOrders ...", [order.id, ...], function(err) { if (err) return cb(err); conn.execute("delete from orders where id=?", [order.id], function(err) { if (err) return cb(err); next(); }); }); }, function() { console.log("orders have been archived"); cb(); }); }); }); }
あなたが書く:
function archiveOrders(date, _) { var conn = db.connect(_); conn.query("select * from orders where date < ?", [date], _).forEach_(_, function(_, order) { conn.execute("insert into archivedOrders ...", [order.id, ...], _); conn.execute("delete from orders where id=?", [order.id], _); }); console.log("orders have been archived"); }
streamline はコードを変換し、コールバックを処理します!
制御フロー API を学ぶ必要はありません。次の簡単なルールに従うだけです。
すべてのコールバックをアンダースコアに置き換え、すべての関数が同期的であるかのようにコードを記述します。
streamline.js の詳細については、ブログ投稿Asynchronous Javascript – the tale of Harry を参照してください。