2017-01-25 6 views
4

Я знаю, что это было предложен здесь много раз и много раз отвечали это не способ, как это должно быть сделано, но еще раз :)JavaScript - синхронизация ждать асинхронной операцию (сон)

Можно ли, каким-то образом вызывать функцию асинхронного вызова (например, вызов таймера/ajax), в основном распространять асинхронную задачу и синхронно ждать, пока она не закончится без использования 100% использования процессора и заблокированного браузера?

Простой ответ достаточно - да или нет. Если нет я не должен писать весь код в зависимости от асинхронной операции в «асинхронном способе» В противном случае, было бы лучше;)

представить себе что-то вроде:

updateCSS("someurl.css") 
 

 
function updateCSS(url) { 
 

 
    var css = getCachedResource(url); 
 

 
    css = css.replace(/regexp/gm, function(curUrl) { 
 
    base64 = atob(getCachedResource(curUrl)) 
 
    return "data:image;base64," + base64 
 
    }) 
 

 
} 
 

 
function getCachedResource(url) { 
 
    
 
    //... 
 
    
 
    if (cached) { 
 
    
 
    return cached 
 
    
 
    } else { 
 
    
 
    // doajax...  
 
    // watfor 
 
    
 
    return loaded 
 
    } 
 
    
 
}

Конечно, Я могу сделать это асинхронным, но код будет ... ужасным. Более того, я должен сделать async все функции, вызывающие эту функцию. Вы видите простое решение? Блокирование было бы проще всего сказать. не

Благодаря

+3

Ответ ** нет **. Добро пожаловать в программирование в JavaScript :) – Pointy

+1

нет абсолютно ничего, что может превратиться асинхронно в синхронное. Если вы остановитесь и подумаете об этом, это понятно. 'код будет ... ужасным' - объять асинхронность, и код снова может быть красивым –

+0

Yup. Грустно :) Я никогда не пойму, почему они не реализовали ожидание async op. – Fis

ответ

0

Как уже отмечалось, короткий ответ нет: Javascript является однопоточных в большинстве сред, в которых он используется. Что вы, что есть случиться, чтобы сделать вашу обработку CSS в другой функции обратного вызова от getCachedResource()

Что-то вроде этого:

function updateCSS(url) { 
    getCachedResource(url, function(css) { 
     // process the css 
    }); 
} 

function getCachedResource(url, done) { 
    //... 
    if (cached) { 
     cachedCSS = ... 
     done(cachedCSS); 
    } else { 
     $.ajax(
     { 
      // ... 
      success: function(result) { 
       // Get the css from the response 
       done(css); 
      } 
      // ... 
     }); 
    } 
} 

Посмотрите на JQuery «отсроченные» объектов или Javascript обещает для более полный способ обработки обратных вызовов

+0

К сожалению, его не только о одиночной потоковой передаче, но и о модели совпадения и цикла событий javascript vm внутренне. Как я уже писал выше, мне нужно было прочитать это сначала: https://developer.mozilla.org/cs/docs/Web/JavaScript/EventLoop , тогда мне было бы ясно, что то, что асинхронно, никогда не может быть выполнено синхронизацией , И неважно, какой шаблон или синтаксический сахар я буду использовать ... Обратные вызовы, обещания, асинхронный, ждут ... Ничто не будет препятствовать возврату функции, все просто ... async и внутренне работает одинаково. Вызов async -> event done-> check error-> call done или код ошибки. – Fis

+0

КПП. Если вы взглянули на мой котелок, основная проблема заключается не в доступе к первому ресурсу, а в ресурсах изображений в следующем «цикле» замены, который должен быть написан совершенно иначе, как в примере, который я вам дал. Это будет что-то вроде get css -> asyncdone -> получить все URL из css в массив -> получить все выделенные ресурсы (кеш/сервер ajax) -> asyncresourcedone -> replace (url, atob (resource)) -> alldone? да, donecallback или, по обещанию вложенности, но реальный кодовый график будет почти таким же. – Fis

+0

Это сдвиг парадигмы: Javascript в среде async действительно не работает, возвращая значения из функции. Он работает, передавая значения следующей функции. В вашем примере вам просто нужно повторить шаблон во внутреннем разделе. Вызвать рутину для получения информации и передать ей новую функцию для обработки результата. Помните также, что функции Javascript имеют доступ к локальным переменным входящих функций –

1

Да.

Вы хотите, чтобы ваш код «спал» до тех пор, пока «асинхронная функция (такая как вызов таймера/ajax) не закончится без использования 100% процессора». Это именно то, что делает async/await.

Другие ответы и комментарии фиксируются на вашей фразе «синхронно ждать», что в JS означает блокирование, но я понимаю, что вы просто хотите избежать реорганизации своего кода «асинхронным способом». Вы хотите писать прямо, не структурируя все как многочисленные обратные вызовы.

Чтобы использовать async/await, вам сначала нужно принять обещания - пространство/время асинхронного JavaScript. Затем вам нужен современный браузер, например Chrome или Firefox Developer Edition, или передайте свой код с помощью Babel js.

Далее вы хотите посмотреть fetch, предлагающий обещание современный способ сделать ajax.

Теперь у вас есть все, что вам нужно. Вот пример, который работает в вышеупомянутых браузерах:

async function fetchy(...args) { 
 
    let response = await fetch(...args); 
 
    if (!response.ok) throw new Error((await response.json()).error_message); 
 
    return response; 
 
} 
 

 
async function showUser(user) { 
 
    let url = `https://api.stackexchange.com/2.2/users/${user}?site=stackoverflow`; 
 
    let item = (await (await fetchy(url)).json()).items[0]; 
 
    console.log(JSON.stringify(item, null, 2)); 
 

 
    let blob = await (await fetchy(item.profile_image)).blob(); 
 
    img.src = URL.createObjectURL(blob); 
 
} 
 

 
input.oninput = async e => await showUser(e.target.value); 
 
showUser(input.value);
<input id="input" type="number" value="918910"></input><br> 
 
<img id="img"></img> 
 
<pre id="pre"></pre>

FYI, fetchy мой помощник для здравомыслящего обработки fetch ошибок.

+1

Я думаю, что вы действительно должны начать свой ответ с «Нет, но» вместо «Да». Ключевое слово 'await' позволяет вашему коду спать/ждать действительно, но не синхронно. – Bergi

+0

@ Bergi Надеюсь, мой ответ прояснит, что означает «да». Вопрос не знает, что он задает, используя «sleep» и «sync wait» в том же предложении (оксюморон в JS). Таким образом, мы должны угадать, что нужно. Я предполагаю, что пользователи с этим вопросом сосны для синхронного * выглядящего * кода, который не является «ужасным». – jib

+0

Вам действительно нужно исправить свой ответ. OP явно просит «синхронно ждать». Это НЕ то, что делает async/await. Он не превращает асинхронный код в синхронный код. Будут выполняться другие обработчики событий. Проблемы параллелизма могут существовать, если вы считаете, что ничего не работает в ожидании результата async. async/await - это просто синтаксический сахар.Он не меняет порядок работы кода. Это просто делает более приятным писать синтаксис для асинхронного кода. – jfriend00

0

Так что просто подытожить ....

Ответ НЕТ.Невозможно заблокировать функцию или любой другой код и дождаться завершения операции async. Механизм для него напрямую не поддерживается виртуальной машиной JavaScript.

Особенно в среде браузера, где невозможно управлять циклом событий виртуальной машины JavaScript (как это возможно с узлом и как на самом деле работает библиотека «deasync»).

Это из-за параллелизм модели и обработки событий JavaScript, как указано здесь:

https://developer.mozilla.org/cs/docs/Web/JavaScript/EventLoop

Это не имеет ничего общего с фактически JavaScript однопоточен.

Также обратите внимание, что все вещи, такие как обещания и новые функции, такие как await/async, - это просто другой способ, как написать/управлять кодом для асинхронных задач. Это не так и никогда не будет полезно для превращения асинхронной синхронизации.

Так что не тратьте время, как я, пытаясь найти способ, как это сделать. Скорее потратите его, разработав асинхронный код;)

0

Просто ответ Ответ: нет.

Не думайте так. думать о производительности бэкэнд, а не делать на стороне клиента.

+0

Невозможно сделать на сервере в моем случае. Backend - это немой «файловый» сервер без вычислительной мощности и возможностей сценариев/кодирования. – Fis

+0

И, кстати, экономия полосы пропускания за счет повторного использования одного и того же изображения через mutliple stylesheets ... backend не может помочь Кроме того, мне не нравятся разработчики, которые говорят: переместите все на backend, мы можем масштабировать там ... и писать код, как свиньи. Я спокойный старый школьный парень от времени, когда каждый сохраненный байт памяти помогал много, и каждый перенесенный байт стоил много денег. К счастью, мы находимся в разное время, но это не значит, что мы не должны эффективно оптимизировать и просто говорить, давайте масштабируем. Особенно, когда клиенты будут достаточно мощными, чтобы выполнять некоторые задачи там (конечно, не для обеспечения безопасности). – Fis

1

No, вы не можете этого сделать даже при использовании 100% -ного использования процессора или заблокированного браузера. Все было специально спроектировано, чтобы вы этого не делали.

Это делает все асинхронный код ядовитым, что означает, что весь код, вызывающий асинхронные функции (как обещание, так и обратный вызов), должен быть асинхронным.

Об ужасном коде: Promise цепей и async/await для спасения, они помогут вам написать асинхронный код с гораздо лучшим синтаксисом. Не бойтесь, используйте async/await, особенно если вы уже используете транспилер.

+0

Это не означает, что обещание или синхронизация/асинхронность сделают его более приятным, чем синхронизация: D Многие другие задачи должны выполняться в async по сравнению с синхронизацией. – Fis

0

Можно ли, как-то, чтобы вызвать функцию асинхронной (например, таймер/АЯКС вызова), в основном общую задачу асинхронной и синхронно ждать, пока не закончится, не имея 100% загрузки процессора и заблокированного браузер?

Нет. Вы не можете «синхронно ждать» результата async в Javascript. Из-за того, что это однопоточный и управляемый событиями дизайн, он просто не сработает.

Поскольку большинство других разговоров/комментариев по этому вопросу носило концептуальный характер, я подумал, что предлагаю ответ о том, как вы практически решите свою конкретную проблему, используя подходящий асинхронный дизайн.

Javascript не предлагает возможность спать, пока заканчивается какая-то длительная деятельность. Таким образом, вы не можете создать свою функцию updateCSS(), чтобы иметь чисто синхронный интерфейс. Вместо этого вам нужно будет использовать асинхронные инструменты в Javascript для разработки интерфейса, который будет работать как в случае кэширования ресурса, так и при использовании ресурса по сети.

Обычный способ проектирования для этого - создать асинхронный интерфейс, и если ресурс будет кэшироваться, вы все равно будете обслуживать его через асинхронный интерфейс. Затем у вас есть один интерфейс, который может использовать вызывающий, и этот интерфейс всегда работает, будет ли кешированный ресурс или нет. Это требует, чтобы вызывающий абонент использовал асинхронный интерфейс.

Практически, вы можете создать как этот getCachedResource():

function getCachedResource(url) { 
    //... 
    if (cached) { 
    // returns a promise who's resolved value is the resource 
    return Promise.resolve(cached); 
    } else { 
    // returns a promise who's resolved value is the resource 
    return doAjax(...); 
    } 
} 

Здесь getCachedResource() всегда возвращает обещание, будет ли в кэше значение или нет. Таким образом, абонент всегда использует интерфейс обещания, как это:

getCachedResource(...).then(function(result) { 
    // use the result here 
}); 

Если результат происходит в кэше, то .then() обработчик будет вызван немедленно (на следующем такте). Если результат будет получен по сети, обработчик .then() будет вызываться, как только будет доступен результат. Вызывающему не нужно беспокоиться о том, где и как был восстановлен ресурс - у них есть один интерфейс для его получения.

В функции updateCSS() вы должны будете разработать для использования асинхронного интерфейса в getCachedResource(). Поскольку ваш текущий дизайн использует синхронный обратный вызов в css.replace(), вам придется переосмыслить это немного, чтобы соответствовать асинхронному поиску. Вот один из способов, как это сделать.

function updateCSS(url) { 
    return getCachedResource(url).then(function(css) { 
     // preflight the replacements we need to do so we know what to fetch 
     var urls = []; 
     css.replace(/regexp/gm, function(curUrl) { 
      urls.push(curUrl); 
     }); 
     // now load all the resources 
     return Promise.all(urls.map(getCachedResource)).then(function(resources) { 
      // now have all the resources, in proper order 
      var index = 0; 
      css = css.replace(/regexp/gm, function(curUrl) { 
       return resources[index++]; 
      }); 
      // final resolved value is the fully loaded css 
      return css; 
     }) 
    }); 
} 

Схема здесь, чтобы запустить фиктивный .replace(), не держать результат, чтобы создать список URL-адресов, которые необходимо загрузить. В зависимости от вашего регулярного выражения это также можно сделать с помощью .match() или .exec(). Затем, как только у вас появится список URL-адресов, вы получите все. Когда у вас есть все они, вы можете запустить .replace() по-настоящему, потому что у вас есть ресурсы, доступные для использования в синхронном обратном вызове .replace().

Один не может затем использовать это так:

updateCss(someCSSURL).then(function(css) { 
    // use the CSS here 
}).catch(function(err) { 
    // process error here 
}); 
+0

Спасибо за много работы, которую вы сделали!Надеюсь, это будет отличный пример для других. Я сделаю это по-другому, потому что не могу (не хочу) использовать обещания :) – Fis

+0

@Fis - Почему бы не использовать обещания? Это современный способ управления асинхронными операциями. – jfriend00

+0

Потому что в моем проекте на данный момент запрещены полисы и все, что с ними связано (вся целая цепочка инструментов, необходимая для создания полного приложения, такого как глоток, webpack и др.) – Fis

Смежные вопросы