LINUX.ORG.RU

javascript избавиться от callback функции

 ,


0

1

Есть ли способ сделать функцию, возвращающую свой результат в callback сделать синхронной?

например есть getValue(name, callback)

function getvalue(name, function(data){ return data[name]; });

как сделать чтобы был возможен такой вариант:

val = getvalue_sync(name);

На ум приходит только обёртка с setInterval. Может есть проверенные решения?

Лучше расскажи что ты делаешь на самом деле.

anonymous
()

А зачем? В чем пруфит?

Aswed ★★★★★
()

Вообще если идея в том что бы писать линейно код, то вот http://bit.ly/1Mzk6ps

anonymous
()

На ум приходит только обёртка с setInterval

Это как интересно?

как сделать чтобы был возможен такой вариант:

Это невозможно, да и не нужно. В некоторых яп можно


aFuture = asyncSend

Но в JS все еще сложней. Эти дебилы со своей «функциональщиной» запароли весь язык, вместо асинхронных сообщений и transparent futures там асинхронные функции, и говнопромисы, синхронизация делается с их помощью, иногда с генераторами вкупе. Последний вариант может сделать что-то похожее синтаксически на то что ты хочешь.

callbackhell
()

Не знаю есть ли такое в js.

google://fiber async
google://EM-Synchrony

anonymous
()

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

Legioner ★★★★★
()
Ответ на: комментарий от Legioner

мсьи, готовые пойти глубже, всегда могут закостылить все, чего «нет» :) Просто это «непопулярное» решение.

slackwarrior ★★★★★
()
Ответ на: комментарий от Legioner

Какая нахрен разница, есть ли нативные потоки или нет, их можно руками реализовать. Твоя ключевая ошибка

В исходной функции надо ждать завершения второго потока

Если ты ждешь, это уже не асинхронный код. Учловно говоря, оператор = и так ждет выполнения присваивания, это блокирующий оператор по-определению. А то что т говоришь, равноценно тому же самому, только с помощью костылей. Спращивается, зачем тогда нужен асинхронный код, если его блокировать.

callbackhell
()
Ответ на: комментарий от Legioner

И то что ты написал, можно и бед многопоточности, нативно сделать, промис как раз этим и занимается, что ждет результат асинхронного кода, только, какая это нафиг синхронность.

callbackhell
()

Есть ли способ сделать функцию, возвращающую свой результат в callback сделать синхронной?

Это невозможно.

Только в частных случаях, когда функция на самом деле синхронная. Тогда можно на колбеке записывать результат во внешнее замыкание.

Vit ★★★★★
()
Ответ на: комментарий от callbackhell

Вот тут дядя запилил такое (как раз то, что ищет ТС): https://alexeypetrushin.github.io/synchronize/docs/index.html

Спращивается, зачем тогда нужен асинхронный код, если его блокировать.

Затем чтобы «так нужно». Ну, и тебе не приходило в голову, что в момент ожидания результата нужной, конкретно этой функции, все остальное крутится асинхронно?

Как пример из вакуума (псевдо-код):

ReadFile(file, FileCallback);
WriteSocket(socket, data, WriteCallback );
ctx = CreateBlockAsyncContext();
WriteFile( file, Xdata, ctx );
result = ctx->wait(); /* вот тут мы ждем когда все завершиться */
... 
Итого, все вместе до ожидания результа выполняется асинхронно. Далее, можно запускать хоть синхронный, хоть асинхронный код. При этом, самое важная часть асинхронщины сохраняется, вызовы FileCallback и WriteCallback могут произойти или до или после ожидания получения значения result.

gh0stwizard ★★★★★
()
Ответ на: комментарий от gh0stwizard

synchronize

А кто то говорил, что асинхроный код нельзя синхронизировать? И не понятно, что там твой дядя запилил, если для этого нативных средств более чем достаточно.

Далее, можно запускать хоть синхронный, хоть

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

А то что ты накалякал в качестве примера, и так пишется на JS, с помощью генераторов, только это совсем не то, о чем речь шла.

callbackhell
()
Ответ на: комментарий от callbackhell

Пока весь синхронный код не выполниться, никакой асинхроный код не запустится, во всеком случае в одном потоке.

А ты хочешь получить что-то другое? Может расскажешь подробнее что ты понимаешь под этим.

А то что ты накалякал в качестве примера, и так пишется на JS, с помощью генераторов, только это совсем не то, о чем речь шла.

Ну, видимо, мы говорим о разных вещах. Меня ты в принципе понял.

gh0stwizard ★★★★★
()
Ответ на: комментарий от gh0stwizard

вызовы FileCallback и WriteCallback могут произойти или до или после ожидания получения значения result.

И да, не могут они произойти ДО, иначе какой смысл в твоей синхронизации? Пиши все асинхронно, если тебя устраивает result == null.

callbackhell
()
Ответ на: комментарий от callbackhell

И да, не могут они произойти ДО, иначе какой смысл в твоей синхронизации?

А мне без разницы в каком порядке они выполнятся. Я не говорил, что ДО они выполняются последовательно.

gh0stwizard ★★★★★
()
Ответ на: комментарий от callbackhell

Да даже если ПОСЛЕ, то они никак не связаны с result. Если нужно сделать будет замыкание (для другого колбека), я бы это написал. Я не это хотел продемонстрировать, но так тоже можно.

gh0stwizard ★★★★★
()
Ответ на: комментарий от gh0stwizard

Может расскажешь подробнее что ты понимаешь под этим.

Да ничего я не понимаю кроме того, что обычно понимается, весь код дефолтно выполняется синхронно, а асинхронные коллбеки кидаются в очередь, и до них выполнение дойдет только после выполнения всего болкирующего кода. Ты утвержлал

Далее, можно запускать хоть синхронный, хоть асинхронный код.

Не ты будешь запускать асинхронный код, а среда выполнения. У тебя понятия детские какие-то.

callbackhell
()
Ответ на: комментарий от gh0stwizard

Если ты говоришь о синхронизации, то к моменту присваивания result асинхронные колбеки должны отработать, и это очевидно.

callbackhell
()
Ответ на: комментарий от callbackhell

Не ты будешь запускать асинхронный код, а среда выполнения. У тебя понятия детские какие-то.

А, ну, вот дошли до среды выполнения. Да, людям приятно читать кода сверху вниз, а не лапшу из колбеков в разных частях кода, размазанных по страницам/экранам, ну, ты понял. Делается это только для того, чтобы удобно было читать код (в 95% случаев). Тем, кому не доставляет лапша неудобства, вообще не замарачиваются с подобной проблемой :) Но, да, вот есть такие люди, которые хотят синхронно асинхронщину на своем экране видеть.

gh0stwizard ★★★★★
()

избавиться от callback функции

но зачем добавлять дополнительные костыли? чем пугает callback?

kiotoze ★★★★
()
Ответ на: комментарий от callbackhell

Если ты говоришь о синхронизации, то к моменту присваивания result асинхронные колбеки должны отработать, и это очевидно.

Нет, это не очевидно. Очевидно только то, что ничего не произодет ниже после строчки result = ctx->wait();. Когда же присваивание будет выполнено, тогда дальше программа продолжит выполнение, кои я задал, в том числе и обработка колбеков для функций в начале (если они еще не завершились). И так, пока не прибьется event loop (неважно как, аварийно или по сигналу, или по хэндлеру ошибок, что угодно).

gh0stwizard ★★★★★
()
Последнее исправление: gh0stwizard (всего исправлений: 1)
Ответ на: комментарий от callbackhell

Какая нахрен разница, есть ли нативные потоки или нет, их можно руками реализовать.

Нельзя.

Если ты ждешь, это уже не асинхронный код. Учловно говоря, оператор = и так ждет выполнения присваивания, это блокирующий оператор по-определению. А то что т говоришь, равноценно тому же самому, только с помощью костылей. Спращивается, зачем тогда нужен асинхронный код, если его блокировать.

Топикстартер и спрашивает, как ему превратить асинхронный код в синхронный. Зачем ему это надо, я не знаю. Я отвечаю на его вопрос.

Legioner ★★★★★
()
Ответ на: комментарий от arturpub

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

callbackhell
()
Ответ на: комментарий от Legioner

Топикстартер и спрашивает, как ему превратить асинхронный код в синхронный

Топикстартер как и миллионы ему подобных, спрашивают странное, как ему синхронно присвоить переменной результат асинхронного вызова.

callbackhell
()
Ответ на: комментарий от callbackhell

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

Поясняю, на том же псевдо-коде:

ReadFile(file, FileCallback); /* висит в воздухе, очереди */
WriteSocket(socket, data, WriteCallback ); /* висит в воздухе, очереди */
ctx = CreateBlockAsyncContext(); /* присваивание происходит моментально */
WriteFile( file, Xdata, ctx ); /* висит в воздухе, очереди */
result = ctx->wait(); /* ждем получения результата для ctx, все остальное вертится-крутится как есть, не трогаем их, игнор */
... 
Т.о. в этом коде нигде ничего не пересекается, никто никого не блокируется и нету волшебства. Этот пример можно легко испортить и тогда произойдет блокирование цикла, например, событие ждет событие. Тут этого нет.

gh0stwizard ★★★★★
()
Ответ на: комментарий от gh0stwizard

ждем получения

Ну так ты же утверждал, что присваивание у тебя происходит не дожидаясь результатов. Ты уж определись что-ли.

callbackhell
()
Ответ на: комментарий от callbackhell

Ну так ты же утверждал, что присваивание у тебя происходит не дожидаясь результатов. Ты уж определись что-ли.

Я так не говорил. Извиняюсь, что неправильно выразился. Ждем результат выполнения колбека ctx и возврата его значения. Сам сtx может быть функцией-пустышкой, которая возращает сразу то, что ей передали.

gh0stwizard ★★★★★
()
Ответ на: комментарий от callbackhell

я хз

О том и речь.

результат выполнения может волшебным образом появиться еще до того, как вычислены необходимые для этого результата данные

Очевидно, что ты знаком с [а]синхронкой только в ее наиболее примитивной форме.

arturpub ★★
()
Ответ на: комментарий от gh0stwizard

тогда ничего нового. В JS можно сделать аналогично



container = new Promise(function(resolve, reject){
  fs.readFile("theFile", "utf8", function(err, data){
     if(err) return reject(err)
     resolve(data)
  })
})

container
 .then(function(r){
   result = r
 })

callbackhell
()
Ответ на: комментарий от arturpub

Относительно обычного синхронного кода, естественно. В современных языках дефолтно код выполняется синхронно, ты не в курсе? man стековые вычисления. Среда выполнения выполняет синхронизацию кода.

callbackhell
()

Решение очевидно - избавься от жаваскрипта, возьми язык с нормально реализованной конкурентностью.

anonymous
()
Ответ на: комментарий от callbackhell

Новое есть и это описано в реализации Promise:

this.done = function (onFulfilled, onRejected) {
    // ensure we are always asynchronous
    setTimeout(function () {
      handle({
        onFulfilled: onFulfilled,
        onRejected: onRejected
      });
    }, 0);
  }

  doResolve(fn, resolve, reject);
}
https://www.promisejs.org/implementing/

С доступом к ассемблерным вставкам реализация отличается. Как раз то, что я и говорил про jmp. Это, как бы, один из вариантов.

gh0stwizard ★★★★★
()
Ответ на: комментарий от arturpub

Очевидно, что ты знаком с [а]синхронкой только в ее наиболее примитивной форме.

А ты, очевидно, с волшебной, где сначала появляется результат, а уже потом вычисляется, lol

callbackhell
()
Ответ на: комментарий от gh0stwizard

Я вообще не понял, к чему твой линк, это никакое не новое, а велосипед. В JS есть нативные промисы. И реализованы они говенно, надо сказать. Но лучше чем ничего.

callbackhell
()
Ответ на: комментарий от gh0stwizard

Тут таймаут как раз про то, чтобы топик стартер не мог писать код который работает с функциями у которых нет асинхронных вызовов, но ломался на тех у которых есть.

zz ★★★★
()
Последнее исправление: zz (всего исправлений: 1)
Ответ на: комментарий от callbackhell

Я вообще не понял, к чему твой линк, это никакое не новое, а велосипед. В JS есть нативные промисы. И реализованы они говенно, надо сказать. Но лучше чем ничего.

Прочитай описание проекта. Велик придуман, чтобы работало максимально везде. Как оно реализовано в нативе, я честно говоря не разбирал. Возможно, там все сделано как надо (читай, через ассемблер, а не велики на JS).

gh0stwizard ★★★★★
()
Последнее исправление: gh0stwizard (всего исправлений: 1)

На то они и коллбэки, что вызвать обратно, когда наступит событие, иначе придется постоянно опрашивать, что жрет ресурсы даром и нагружает проц ...

anonymous
()
Ответ на: комментарий от callbackhell

Относительно обычного синхронного кода, естественно.

Всего? Или относительно синхронного кода здесь ниже и только в этом стеке вызовов?

В современных языках дефолтно код выполняется синхронно, ты не в курсе?

Открой для себя не «код» (детский сад бладж), а логические потоки исполнения.

Например ты решил обновить данные в таблице, отправив запрос серверу, а пока суть да дело пользователь выделил диапазон и тебе надо для каждой ячейки пройти по урл и что-то там забрать для суммирования. Первая задача пусть будет А, вторая Б.

В случае с колбэками у тебя для потока А будет две функции — первая А1 отправляет запрос, а вторая А2 захватывает контекст и будет вызвана по ответу. Для Б будет точка входа Б0, куча продолжений от запросов Б1..БN и суммирование Бs. Если присмотреться, то увидишь, что A = A1A2, а Б = Б0Б?{N}Бs, вполне себе линейные потоки, друг от друга не зависящие никак, при этом Б еще и на порядок свой плевала с высокой колокольни.

В случае с легкими тредами у тебя для потока А будет одна функция, примерно такая (жс-лайк псевдокод):

function A() {
    var t = get_current_light_thread();
    send_request(address, request, function(result) { t(result); });
    var result = yield();
    update_table(result);
}

Или короче:

function send_request_wait(address, request) {
    var t = get_current_light_thread();
    send_request(address, request, function(result) { t(result); });
    return yield();
}

function A() {
    update_table(send_request_wait(address, request));
}

Для потока Б чуть сложнее, но тоже одна (и с явным элементом синхронизации):

function send_request_group(address, request, group) {
    var t = get_current_light_thread();
    if (!defined(group.results)) group.results = [ ];
    group.n += 1;
    send_request(address, request, function(result) {
        group.results.add(result);
        if (0 == (group.n -= 1)) t(group.results);
    });
}

function B() {
    var group = { };
    for (i = 0; i < n; i++)
        send_request_group(address, request, group);
    var results = yield();
    label1.set_text(sum(results));
}

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

arturpub ★★
()
Последнее исправление: arturpub (всего исправлений: 1)
Ответ на: комментарий от arturpub

Но в жабоскрипте yield работает только для протокола генераторов, насколько я понимаю из быстрого гугления, а нормальной кооперативности в него похоже так и не завезут.

принципиальной разницы нет, просто больше писанины.

но не надо произносить слов «современных языках» и «синхронизация»

Я не понял, к чему ты это все накатал. По твоему легкие треды отменяют дефолтный синхронный код или что? Поясняю популярно, что такое синхронныйй и асинхронный код.

//асинхронный:
doStuff1 // вычисление началось, не ждем результата, сразу переходим к следующей строке
doStuff2 

//синхронный:
doStuff1 // пока не дождемся результата, никакой другой код не выполняется, следуюшая строка ждет
doStuff2 

//или
асинхронный:
fu(someCode) //someCode бросается в очередь, fu получает и отдает undefined, поток выполнения переходит к следующей строке, someCode выполнится позже
nextString

асинхронный:
fu(someCode) //fu "ждет" исполнения тела с аргументом, возвращает результат и только после этого переходим к nextString.
nextString
callbackhell
()
Ответ на: комментарий от arturpub

К слову, синхронный блокирующий код и стековые вычисления по дефолту — это вообще фундаментальная ошибка. В модели Акторов любое сообщение асинхронно по дефолту. Но имеем то что имеем. Код в современных ЯП выполняется синхронно, если не указано иное. А yield, собственно, непосредственного отношения к асинхронности не имеет. Это, просто метка для выхода из сопрограммы.

callbackhell
()

На ум приходит только обёртка с setInterval

С этого места подробнее хотелось бы. setInterval же и сам асихронен. А вообще - тру-синхронности не получишь, но есть async и прочие promis-ы.

alex4321
()

Оберни асинхронную функцию в свою синхронную. Делов то . . .

Int0l ★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.