Синхронный Вызов Асинхронной Функции Javascript
во-первых, это очень специфический случай, когда это делается неправильно по назначению, чтобы модернизировать асинхронный вызов в очень синхронную кодовую базу, которая имеет много тысяч строк, и время в настоящее время не позволяет вносить изменения в "Делать это правильно.- Это ранит каждую клеточку моего существа,но реальность и идеалы часто не сходятся. Я знаю, что это отстой.
хорошо, что из пути, как мне сделать это, чтобы я мог:
function doSomething() {
var data;
function callBack(d) {
data = d;
}
myAsynchronousCall(param1, callBack);
// block here and return data when the callback is finished
return data;
}
примеры (или отсутствие все они используют библиотеки и / или компиляторы, оба из которых не являются жизнеспособными для этого решения. Мне нужен конкретный пример того, как сделать его блокирующим (например, не оставлять функцию doSomething до тех пор, пока не будет вызван обратный вызов), не замораживая пользовательский интерфейс. Если такое возможно в JS.
6 ответов:
"не говорите мне о том, как я должен просто сделать это "правильный путь" или что"
ОК. но вы действительно должны сделать это правильный путь... или что-то еще
мне нужен конкретный пример того, как это сделать блок ... Без замораживания пользовательского интерфейса. Если такое возможно в JS."
нет, невозможно заблокировать запущенный JavaScript без блокировка пользовательского интерфейса.
учитывая недостаток информации, трудно предложить решение, но один из вариантов может заключаться в том, чтобы вызывающая функция выполняла некоторый опрос для проверки глобальной переменной, а затем устанавливала обратный вызов
dataдо глобального.function doSomething() { // callback sets the received data to a global var function callBack(d) { window.data = d; } // start the async myAsynchronousCall(param1, callBack); } // start the function doSomething(); // make sure the global is clear window.data = null // start polling at an interval until the data is found at the global var intvl = setInterval(function() { if (window.data) { clearInterval(intvl); console.log(data); } }, 100);все это предполагает, что вы можете изменить
doSomething(). Я не знаю, есть ли это в картах.если его можно изменить, то я не знаю, почему бы вам просто не передать обратный вызов
doSomething()из других перезвони, но мне лучше остановиться, пока я не попал в беду. ;)
О, черт. Вы привели пример, который предполагает, что это может быть сделано правильно, поэтому я собираюсь показать это решение...
function doSomething( func ) { function callBack(d) { func( d ); } myAsynchronousCall(param1, callBack); } doSomething(function(data) { console.log(data); });поскольку ваш пример включает обратный вызов, который передается асинхронному вызову, правильным способом было бы передать функцию в
doSomething()для вызова из обратного вызова.конечно, если это единственное, что делает обратный вызов, вы просто передадите
funcнепосредственно...myAsynchronousCall(param1, func);
взгляните на обещания JQuery:
http://api.jquery.com/promise/
http://api.jquery.com/jQuery.when/
http://api.jquery.com/deferred.promise/
рефакторинг кода:
var dfd = new jQuery.Deferred(); function callBack(data) { dfd.notify(data); } // do the async call. myAsynchronousCall(param1, callBack); function doSomething(data) { // do stuff with data... } $.when(dfd).then(doSomething);
асинхронные функции функция в ES2017, сделать асинхронный код выглядеть синхронизации с помощью обещания (особая форма асинхронного кода) и
awaitключевое слово. Также обратите внимание в примерах кода под ключевым словомasyncпередfunctionключевое слово, которое обозначает функцию async / await. Элементawaitключевое слово не будет работать, не будучи в функции предварительно фиксированной сasyncключевое слово. Поскольку в настоящее время нет исключения из этого, что означает нет верхний уровень ждет будет работать (верхний уровень ждет означает ожидание вне любой функции). Хотя есть и
есть один хороший обходной путь в http://taskjs.org/
Он использует генераторы, которые являются новыми для JavaScript. Так что в настоящее время он не реализован в большинстве браузеров. Я тестировал его в firefox, и для меня это хороший способ обернуть асинхронную функцию.
вот пример кода из проекта GitHub
var { Deferred } = task; spawn(function() { out.innerHTML = "reading...\n"; try { var d = yield read("read.html"); alert(d.responseText.length); } catch (e) { e.stack.split(/\n/).forEach(function(line) { console.log(line) }); console.log(""); out.innerHTML = "error: " + e; } }); function read(url, method) { method = method || "GET"; var xhr = new XMLHttpRequest(); var deferred = new Deferred(); xhr.onreadystatechange = function() { if (xhr.readyState === 4) { if (xhr.status >= 400) { var e = new Error(xhr.statusText); e.status = xhr.status; deferred.reject(e); } else { deferred.resolve({ responseText: xhr.responseText }); } } }; xhr.open(method, url, true); xhr.send(); return deferred.promise; }
идея, которую вы надеетесь достичь, может быть сделана возможной, если вы немного измените требование
приведенный ниже код возможен, если среда выполнения поддерживает спецификацию ES6.
подробнее о асинхронные функции
async function myAsynchronousCall(param1) { // logic for myAsynchronous call return d; } function doSomething() { var data = await myAsynchronousCall(param1); //'blocks' here until the async call is finished return data; }
вы можете использовать рекурсию, просто создайте функцию, которая вызывает себя, вызовите эту функцию 1 раз извне, внутри рекурсивной функции вызовите свой асинхронный код, повторите свою рекурсивную функцию с помощью обратных вызовов.
Comments