Как обернуть вызовы асинхронных функций в функцию синхронизации в Node.js или Javascript?

Предположим, вы поддерживаете библиотеку, которая предоставляет функцию getData. Ваши пользователи вызывают его для получения фактических данных:
var output = getData();
Внутренние данные сохраняются в файле, поэтому вы реализовали getData с помощью встроенного в Node.js fs.readFileSync. Очевидно, что и getData, и fs.readFileSync являются функциями синхронизации. Однажды вам сказали переключить базовый источник данных на репо, такое как MongoDB, к которому можно получить доступ только асинхронно. Вам также сказали, чтобы пользователи не злили, getData API нельзя изменить так, чтобы он возвращал просто обещание или требовал параметр обратного вызова. Как вы соответствуете обоим требованиям?

Асинхронная функция с использованием обратного вызова / обещания - это ДНК JavasSript и Node.js. Любое нетривиальное JS-приложение, вероятно, пронизано этим стилем кодирования. Но такая практика легко может привести к так называемой пирамиде гибели обратных вызовов. Хуже того, если какой-либо код в любом вызывающем абоненте в цепочке вызовов зависит от результата асинхронной функции, этот код также должен быть заключен в функцию обратного вызова, налагая ограничение стиля кодирования на вызывающего. Время от времени я обнаруживаю необходимость инкапсулировать асинхронную функцию (часто предоставляемую в сторонней библиотеке) в функцию синхронизации, чтобы избежать массового глобального повторного факторинга. Поиск решения по этой теме обычно заканчивался Node Fibers или пакетами npm, созданными на его основе. Но Fibers просто не могут решить проблему, с которой я столкнулся. Даже пример, приведенный автором Фиберса, проиллюстрировал этот недостаток:

...
Fiber(function() {
    console.log('wait... ' + new Date);
    sleep(1000);
    console.log('ok... ' + new Date);
}).run();
console.log('back in main');

Фактический выход:

wait... Fri Jan 21 2011 22:42:04 GMT+0900 (JST)
back in main
ok... Fri Jan 21 2011 22:42:05 GMT+0900 (JST)

Если функция Fiber действительно переводит спящий режим асинхронной функции в синхронизацию, вывод должен быть:

wait... Fri Jan 21 2011 22:42:04 GMT+0900 (JST)
ok... Fri Jan 21 2011 22:42:05 GMT+0900 (JST)
back in main

Я создал еще один простой пример в JSFiddle и ищу код для получения ожидаемого результата. Я приму решение, которое работает только в Node.js, поэтому вы можете потребовать любой пакет npm, несмотря на то, что он не работает в JSFiddle.


person abbr    schedule 17.02.2014    source источник
comment
Это невозможно без доступа к некоторому API нижнего уровня движка JavaScript. Например. для надстроек Firefox существует модуль, позволяющий синхронизировать асинхронные функции путем доступа к некоторому объекту потока. Вы можете открыть следующий URL-адрес в Firefox и посмотреть: resource: //services-common/async.js. Но в обычном JavaScript это невозможно.   -  person Felix Kling    schedule 17.02.2014
comment
Асинхронные функции никогда нельзя сделать синхронными в Node, и даже если бы это было возможно, вам не следует этого делать. Проблема в том, что в модуле fs можно увидеть совершенно отдельные функции для синхронного и асинхронного доступа к файловой системе. Лучшее, что вы можете сделать, - это замаскировать появление асинхронности с помощью обещаний или сопрограмм (генераторов в ES6). Для управления пирамидами обратного вызова дайте им имена вместо определения в вызове функции и используйте что-то вроде библиотеки async.   -  person qubyte    schedule 17.02.2014
comment
asynch не должен добавлять сложности, это просто означает выполнение вашей работы слева от a}), а не справа.   -  person dandavis    schedule 17.02.2014
comment
Именно модуль fs заставляет меня найти эту потребность. В проекте Node, созданном мной FormMailerService, сначала я реализовал сохранение данных с помощью sync fs. Позже я решил добавить MongoDB с помощью Mongoose. Но Mongoose поддерживает только асинхронное соединение с базой данных. Я закончил с неприятным рефакторингом кода, и пирамида обратного вызова обречена на вид здесь   -  person abbr    schedule 17.02.2014
comment
Для dandavis async всплывает детали реализации в цепочку вызовов, иногда вызывая глобальный рефакторинг. Это губительно и даже катастрофично для сложного приложения, где важны модульность и локализация.   -  person abbr    schedule 17.02.2014
comment
Но эта практика может легко привести к так называемой пирамиде обратного вызова, если вы не используете правильную организацию очереди. Для асинхронного поведения «годен-сбой» вместо этого следует использовать обещания. Просьба сделать асинхронный код синхронным для меня звучит как проблема XY.   -  person zzzzBov    schedule 17.02.2014
comment
Пирамида гибели обратных вызовов - это только представление о проблеме. Promise может скрыть или замаскировать его, но не может решить истинную проблему: если вызывающий объект асинхронной функции зависит от результатов асинхронной функции, он должен использовать обратный вызов, как и его вызывающий объект и т. Д. Это классический пример наложения ограничений на вызывающий абонент просто из-за деталей реализации.   -  person abbr    schedule 17.02.2014
comment
Вот почему рекомендуется начинать с обещаний с самого начала. Вы можете изменить реализацию, не затрагивая вызывающего.   -  person Felix Kling    schedule 17.02.2014
comment
Это не всегда вариант. См. Сценарий, который я дал в первом параграфе вопроса.   -  person abbr    schedule 19.02.2014
comment
@abbr: Спасибо за модуль deasync, описание вашей проблемы - это именно то, что я искал и не мог найти никаких работоспособных решений. Я возился с генераторами и итерациями, но пришел к тем же выводам, что и вы.   -  person Kevin Jhangiani    schedule 14.09.2015
comment
Стоит отметить, что почти никогда не бывает хорошей идеей принудительно синхронизировать асинхронную функцию. У вас почти всегда есть лучшее решение, которое сохраняет асинхронность функции неизменной, при этом обеспечивая тот же эффект (например, последовательность, установка переменных и т. Д.).   -  person Madara's Ghost    schedule 26.11.2015
comment
Другой типичный вариант использования: вы пишете плагин фильтра для фреймворка, который ожидает обратного вызова с немедленным результатом. В моем случае Hexo фильтрует HTML после рендеринга. Но чтобы создать свой фильтр, вам нужно вызвать асинхронный API (PostHTML) ...   -  person PhiLho    schedule 11.01.2016


Ответы (10)


deasync превращает асинхронную функцию в синхронизацию, реализованную с помощью механизма блокировки, путем вызова цикла событий Node.js на уровне JavaScript. В результате deasync только блокирует выполнение последующего кода, не блокируя весь поток и не вызывая ожидания занятости. С помощью этого модуля вот ответ на вызов jsFiddle:

function AnticipatedSyncFunction(){
  var ret;
  setTimeout(function(){
      ret = "hello";
  },3000);
  while(ret === undefined) {
    require('deasync').runLoopOnce();
  }
  return ret;    
}


var output = AnticipatedSyncFunction();
//expected: output=hello (after waiting for 3 sec)
console.log("output="+output);
//actual: output=hello (after waiting for 3 sec)

(отказ от ответственности: я являюсь соавтором deasync. Модуль был создан после публикации этого вопроса и не нашел работоспособного предложения.)

person abbr    schedule 11.03.2014
comment
Кому-нибудь еще повезло с этим? Я не могу заставить это работать. - person newman; 02.05.2015
comment
Я не могу заставить его работать должным образом. вам следует улучшить свою документацию по этому модулю, если вы хотите, чтобы он использовался чаще. Я сомневаюсь, что авторы точно знают, каковы последствия использования модуля, а если и знают, то определенно не документируют их. - person Alexander Mills; 02.06.2015
comment
Пока есть одна подтвержденная проблема, задокументированная в трекере проблем github. Проблема исправлена ​​в Node v0.12. Остальное, что я знаю, - это просто беспочвенные предположения, которые не стоит документировать. Если вы считаете, что ваша проблема вызвана деасинхронизацией, опубликуйте автономный дублируемый сценарий, и я изучу его. - person abbr; 26.06.2015
comment
Я попытался использовать его и получил некоторые улучшения в моем сценарии, но мне все равно не повезло с датой. Я изменил код следующим образом: function AnticipatedSyncFunction(){ var ret; setTimeout(function(){ var startdate = new Date() //console.log(startdate) ret = "hello" + startdate; },3000); while(ret === undefined) { require('deasync').runLoopOnce(); } return ret; } var output = AnticipatedSyncFunction(); var startdate = new Date() console.log(startdate) console.log("output="+output); и ожидаю увидеть разницу в 3 секунды в выводе даты! - person Alex; 13.09.2016
comment
@abbr можно просматривать и использовать без зависимости от узлов › - person Gandhi; 06.06.2017
comment
@ Ганди, нет. Это зависит от nodejs. - person abbr; 07.06.2017
comment
@abbr спасибо за ответ. Есть ли способ добиться синхронного вызова функции с использованием ванильного JavaScript? - person Gandhi; 08.06.2017
comment
@Alex внимательно прочтите developer.mozilla.org/en-US/docs/ Web / JavaScript / EventLoop до этого ожидает ровно 3000 мсек от setTimeout в сочетании с хаками js-движка. :-) - person user1742529; 17.08.2020

Также существует модуль синхронизации npm. который используется для синхронизации процесса выполнения запроса.

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

Образец кода

/*require sync module*/
var Sync = require('sync');
    app.get('/',function(req,res,next){
      story.find().exec(function(err,data){
        var sync_function_data = find_user.sync(null, {name: "sanjeev"});
          res.send({story:data,user:sync_function_data});
        });
    });


    /*****sync function defined here *******/
    function find_user(req_json, callback) {
        process.nextTick(function () {

            users.find(req_json,function (err,data)
            {
                if (!err) {
                    callback(null, data);
                } else {
                    callback(null, err);
                }
            });
        });
    }

справочная ссылка: https://www.npmjs.com/package/sync

person sanjeev kumar    schedule 19.12.2016

Вы должны использовать обещания:

const asyncOperation = () => {
    return new Promise((resolve, reject) => {
        setTimeout(()=>{resolve("hi")}, 3000)
    })
}

const asyncFunction = async () => {
    return await asyncOperation();
}

const topDog = () => {
    asyncFunction().then((res) => {
        console.log(res);
    });
}

Мне больше нравятся определения стрелочных функций. Но любую строку вида «() => {...}» можно также записать как «function () {...}»

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

введите описание изображения здесь

РЕДАКТИРОВАТЬ: Я понимаю, что во многих случаях вам нужно обернуть асинхронную функцию внутри функции синхронизации внутри контроллера. Для таких ситуаций есть трюк для вечеринки:

const getDemSweetDataz = (req, res) => {
    (async () => {
        try{
            res.status(200).json(
                await asyncOperation()
            );
        }
        catch(e){
            res.status(500).json(serviceResponse); //or whatever
        }
    })() //So we defined and immediately called this async function.
}

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

const asyncOperation = () => {
    return new Promise((resolve, reject) => {
        setTimeout(()=>{resolve("hi")}, 3000)
    })
}

const asyncFunction = async (callback) => {
    let res = await asyncOperation();
    callback(res);
}

const topDog = () => {
    let callback = (res) => {
        console.log(res);
    };

    (async () => {
        await asyncFunction(callback)
    })()
}

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

person user2485309    schedule 07.05.2018

Если функция Fiber действительно превращает спящий режим асинхронной функции в синхронизацию

да. Внутри волокна функция ожидает перед регистрацией ok. Волокна не делают асинхронные функции синхронными, но позволяют писать синхронно выглядящий код, который использует асинхронные функции, а затем будет выполняться асинхронно внутри Fiber.

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

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

Моя цель - минимизировать влияние на вызывающего абонента при изменении метода сбора данных с синхронизации на асинхронный.

И обещания, и волокна могут это сделать.

person Bergi    schedule 17.02.2014
comment
это АБСОЛЮТНО худшее, что вы можете сделать с Node.js: синхронно выглядящий код, который использует асинхронные функции, а затем будет выполняться асинхронно. если ваш API сделает это, вы разрушите жизнь. если он асинхронный, он должен требовать обратного вызова и выдавать ошибку, если обратный вызов не предоставляется. это лучший способ создать API, если ваша цель - обмануть людей. - person Alexander Mills; 02.06.2015
comment
@AlexMills: Да, это было бы действительно ужасно. Однако, к счастью, это не то, что API может сделать. Асинхронный API всегда должен принимать обратный вызов / возвращать обещание / ожидать, что он будет запущен внутри волокна - без него он не работает. Afaik, волокна в основном использовались в быстрых и грязных сценариях, которые блокировали и не имели параллелизма, но хотели использовать асинхронные API; как и в узле, иногда бывают случаи, когда вы используете синхронные fs методы. - person Bergi; 02.06.2015
comment
Мне вообще нравится node. Особенно, если я могу использовать машинописный текст вместо чистого js. Но вся эта бессмыслица с асинхронностью, которая пронизывает все, что вы делаете, и буквально заражает каждую функцию в цепочке вызовов, как только вы решаете сделать единственный вызов async, - это то, что я действительно ... очень ненавижу. Async api похож на инфекционное заболевание: один вызов заражает всю вашу базу кода, вынуждая вас переписать весь имеющийся у вас код. Я действительно не понимаю, как можно утверждать, что это хорошая вещь. - person Kris; 29.05.2018
comment
@Kris Node использует асинхронную модель для задач ввода-вывода, потому что это быстро и просто. Вы также можете делать многие вещи синхронно, но блокировка происходит медленно, поскольку вы не можете ничего делать одновременно - если вы не используете потоки, которые все усложняют. - person Bergi; 29.05.2018
comment
@Bergi Я прочитал манифест, поэтому я знаю аргументы. Но изменить существующий код на асинхронный в тот момент, когда вы нажмете этот первый вызов api, который не имеет эквивалента синхронизации, непросто. Все ломается, и каждую строчку кода нужно тщательно изучить. Если ваш код не является тривиальным, я гарантирую ... потребуется некоторое время, чтобы преобразовать и заставить его снова работать после преобразования всего этого в асинхронную идиому. - person Kris; 30.05.2018

В настоящее время этот шаблон генератора может быть решением во многих ситуациях.

Вот пример последовательных подсказок консоли в nodejs с использованием функции async readline.question:

var main = (function* () {

  // just import and initialize 'readline' in nodejs
  var r = require('readline')
  var rl = r.createInterface({input: process.stdin, output: process.stdout })

  // magic here, the callback is the iterator.next
  var answerA = yield rl.question('do you want this? ', r=>main.next(r))    

  // and again, in a sync fashion
  var answerB = yield rl.question('are you sure? ', r=>main.next(r))        

  // readline boilerplate
  rl.close()

  console.log(answerA, answerB)

})()  // <-- executed: iterator created from generator
main.next()     // kick off the iterator, 
                // runs until the first 'yield', including rightmost code
                // and waits until another main.next() happens
person drodsou    schedule 17.08.2016

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

Давайте посмотрим на пример: Предположим, вы используете некую структуру, которая является точкой входа в ваше приложение (вы не можете изменить эту структуру). Эта структура загружает модули nodejs как плагины и вызывает некоторые методы в плагинах. Допустим, эта структура принимает только синхронные функции и не использует сами по себе волокна.

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

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

Оборотная сторона: если фреймворк внутренне использует setTimeout или Promises, он выйдет из контекста волокна. Это можно обойти, высмеивая setTimeout, Promise.then и все обработчики событий.

Вот как вы можете отдавать волокно, пока не будет разрешено Promise. Этот код принимает асинхронную функцию (возврат обещания) и возобновляет работу волокна, когда обещание разрешено:

framework-entry.js

console.log(require("./my-plugin").run());

async-lib.js

exports.getValueAsync = () => {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve("Async Value");
    }, 100);
  });
};

my-plugin.js

const Fiber = require("fibers");

function fiberWaitFor(promiseOrValue) {
  var fiber = Fiber.current, error, value;
  Promise.resolve(promiseOrValue).then(v => {
    error = false;
    value = v;
    fiber.run();
  }, e => {
    error = true;
    value = e;
    fiber.run();
  });
  Fiber.yield();
  if (error) {
    throw value;
  } else {
    return value;
  }
}

const asyncLib = require("./async-lib");

exports.run = () => {
  return fiberWaitFor(asyncLib.getValueAsync());
};

my-entry.js

require("fibers")(() => {
  require("./framework-entry");
}).run();

При запуске node framework-entry.js будет выдана ошибка: Error: yield() called with no fiber running. Если вы запустите node my-entry.js, он работает должным образом.

person Tamas Hegedus    schedule 14.07.2016

Вам следует смотреть не на то, что происходит вокруг вызова, создающего волокно, а скорее на то, что происходит внутри волокна. Как только вы окажетесь внутри волокна, вы можете программировать в стиле синхронизации. Например:

function f1() {
    console.log('wait... ' + new Date);
    sleep(1000);
    console.log('ok... ' + new Date);   
}

function f2() {
    f1();
    f1();
}

Fiber(function() {
    f2();
}).run();

Внутри волокна вы вызываете f1, f2 и sleep, как если бы они были синхронизированы.

В типичном веб-приложении вы создадите Fiber в диспетчере HTTP-запросов. Как только вы это сделаете, вы можете написать всю свою логику обработки запросов в стиле синхронизации, даже если она вызывает асинхронные функции (fs, базы данных и т. Д.).

person Bruno Jouhier    schedule 17.02.2014
comment
Спасибо, Бруно. Но что, если мне нужен стиль синхронизации в коде начальной загрузки, который должен быть выполнен до того, как сервер привяжется к порту tcp - например, конфигурация или данные, которые должны быть прочитаны из базы данных, которая открывается асинхронно? Я мог закончить тем, что обернул весь server.js в Fiber, и я подозреваю, что это убьет параллелизм на уровне всего процесса. Тем не менее, это предложение стоит проверить. Для меня идеальное решение должно иметь возможность обернуть асинхронную функцию, чтобы обеспечить синтаксис вызова синхронизации и блокировать только следующие строки кода в цепочке вызывающих, не жертвуя параллелизмом на уровне процесса. - person abbr; 17.02.2014
comment
Вы можете заключить весь код начальной загрузки в один большой вызов Fiber. Параллелизм не должен быть проблемой, потому что код начальной загрузки обычно необходимо выполнить до завершения, прежде чем вы начнете обслуживать запросы. Кроме того, волокно не препятствует запуску других волокон: каждый раз, когда вы нажимаете вызов yield, вы даете другим волокнам (и основному потоку) возможность работать. - person Bruno Jouhier; 18.02.2014
comment
Я обернул файл Express bootstrap server.js с помощью fiber. Последовательность выполнения - это то, что я ищу, но этот перенос никак не влияет на обработчик запросов. Поэтому я думаю, что нужно применить одну и ту же оболочку к КАЖДОМУ диспетчеру. Я сдался на этом этапе, потому что, похоже, это не помогает избежать глобального рефакторинга. Моя цель - минимизировать влияние на вызывающего абонента, когда метод сбора данных меняется с синхронного на асинхронный на уровне DAO, а Fiber все еще не справляется с задачей. - person abbr; 18.02.2014
comment
@fred: Нет смысла синхронизировать потоки событий, такие как обработчик запросов - вам понадобится цикл while(true) handleNextRequest(). Оборачивание каждого обработчика запросов в волокно сделало бы. - person Bergi; 18.02.2014
comment
@fred: фибры не очень помогут вам с Express, потому что обратный вызов Express не является обратным вызовом продолжения (обратный вызов, который всегда вызывается ровно один раз, либо с ошибкой, либо с результатом). Но фибры разрешат пирамиду гибели, если у вас есть много кода, написанного поверх асинхронных API с обратными вызовами продолжения (такими как fs, mongodb и многие другие). - person Bruno Jouhier; 19.02.2014

Синхронизация кода Node.js важна в нескольких аспектах, таких как база данных. Но реальное преимущество Node.js заключается в асинхронном коде. Поскольку это однопоточный неблокирующий.

мы можем синхронизировать его, используя важные функции Fiber () Используйте await () и defer (), мы вызываем все методы, используя await (). затем замените функции обратного вызова на defer ().

Обычный асинхронный код, использующий функции обратного вызова.

function add (var a, var b, function(err,res){
       console.log(res);
});

 function sub (var res2, var b, function(err,res1){
           console.log(res);
    });

 function div (var res2, var b, function(err,res3){
           console.log(res3);
    });

Синхронизируйте приведенный выше код с помощью Fiber (), await () и defer ()

fiber(function(){
     var obj1 = await(function add(var a, var b,defer()));
     var obj2 = await(function sub(var obj1, var b, defer()));
     var obj3 = await(function sub(var obj2, var b, defer()));

});

Я надеюсь, это поможет. Спасибо

person Mohan Ramakrishna    schedule 14.07.2015

Сначала я боролся с этим с помощью node.js, а async.js - лучшая библиотека, которую я нашел, чтобы помочь вам справиться с этим. Если вы хотите писать синхронный код с помощью узла, подход следующий.

var async = require('async');

console.log('in main');

doABunchOfThings(function() {
  console.log('back in main');
});

function doABunchOfThings(fnCallback) {
  async.series([
    function(callback) {
      console.log('step 1');
      callback();
    },
    function(callback) {
      setTimeout(callback, 1000);
    },
    function(callback) {
      console.log('step 2');
      callback();
    },
    function(callback) {
      setTimeout(callback, 2000);
    },
    function(callback) {
      console.log('step 3');
      callback();
    },
  ], function(err, results) {
    console.log('done with things');
    fnCallback();
  });
}

эта программа ВСЕГДА будет производить следующее ...

in main
step 1
step 2
step 3
done with things
back in main
person Michael Connor    schedule 01.05.2014
comment
async работает в вашем примере b / c это main, который не заботится о вызывающем. Представьте, что весь ваш код заключен в функцию, которая должна возвращать результат одного из вызовов вашей асинхронной функции. Его можно легко проверить, добавив console.log('return'); в конце вашего кода. В таком случае вывод return произойдет после in main, но до step 1. - person abbr; 02.05.2014

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

Научитесь любить асинхронный код!

Взгляните на promises для асинхронного кода без создания пирамиды ада обратного вызова. Я рекомендую библиотеку PromiseQ для node.js

httpGet(url.parse("http://example.org/")).then(function (res) {
    console.log(res.statusCode);  // maybe 302
    return httpGet(url.parse(res.headers["location"]));
}).then(function (res) {
    console.log(res.statusCode);  // maybe 200
});

http://howtonode.org/promises

РЕДАКТИРОВАТЬ: это, безусловно, мой самый спорный ответ, теперь у узла есть ключевое слово yield, которое позволяет обрабатывать асинхронный код, как если бы он был синхронным. http://blog.alexmaccaw.com/how-yield-will-transform-node

person roo2    schedule 17.02.2014
comment
Promise только перефразирует параметр обратного вызова, а не превращает функцию в синхронизацию. - person abbr; 17.02.2014
comment
вы не хотите, чтобы это синхронизировалось, иначе весь ваш сервер заблокируется! stackoverflow.com/questions/17959663/ - person roo2; 17.02.2014
comment
Желательно, чтобы вызов синхронизации не блокировал другие события, такие как другой запрос, обрабатываемый Node.js. Функция Sync по определению означает только то, что она не вернется к вызывающей стороне, пока не будет получен результат (а не просто обещание). Он не исключает заранее сервер из обработки других событий, пока вызов заблокирован. - person abbr; 17.02.2014
comment
@fred: я думаю, вы упускаете суть обещаний. Это не просто абстракция шаблона наблюдателя, но они предоставляют способ связывать и составлять асинхронные действия. - person Bergi; 17.02.2014
comment
@Bergi, я много использую обещание и точно знаю, что он делает. Фактически все, что он достиг, - это разбиение одного вызова асинхронной функции на несколько вызовов / операторов. Но это не меняет результата - когда вызывающий объект возвращается, он не может вернуть результат асинхронной функции. Посмотрите пример, который я опубликовал в JSFiddle. Вызывающим в этом случае является функция AnticipatedSyncFunction, а асинхронной функцией - setTimeout. Если вы можете ответить на мой вызов с помощью обещания, пожалуйста, покажите мне. - person abbr; 18.02.2014
comment
@fred: Ничто не может return быть результатом асинхронной функции. - person Bergi; 18.02.2014
comment
Тогда не обещай :). Но все равно спасибо за усилия. - person abbr; 18.02.2014
comment
@Bergi Существует как минимум 3 технических подхода, которые делают возможным return из асинхронной функции: # 1 волокна, # 2 генераторы, # 3 преобразования CPS. - person Bruno Jouhier; 19.02.2014
comment
Но может ли какой-либо подход решить проблему, которую я поставил в первом абзаце моего вопроса? Если да, то на мой пример JSFiddle не составит труда дать ответ по коду. Пока не получил. - person abbr; 19.02.2014
comment
@fred Нет ничего, что могло бы решить вашу проблему, как указано, со всеми ее ограничениями (хотя вы не полностью исключили переопределение setTimeout с помощью глупого блокирующего вызова, который привязывает процессор). Но это не значит, что решения (CPS, волокна, генераторы) ничего не стоят. Они решают проблему с немного меньшими ограничениями. С другой стороны, одни только обещания не избавляют вас от необходимости обратного вызова везде, где возвращается значение. - person Bruno Jouhier; 22.02.2014
comment
@Bruno, я склонен полагать, что сейчас нет практического решения. Но я не считаю, что это теоретически невозможно - синхронизация и параллелизм не исключают друг друга даже в одном потоке. Хороший программист на C / C ++ должен уметь создать пакет npm, похожий на Fibers, чтобы ответить на мою задачу. А пока лучшее решение, которое я могу придумать, - это принять фреймворк, который глубоко включает волокна на очень ранней стадии стека вызовов. Я считаю, что Meteor - один из таких фреймворков, и мою проблему можно решить с помощью функции Meteor._wrapAsync (). Или еще лучше, включите Fibers в ядро ​​Node.js. - person abbr; 23.02.2014
comment
Волокна @EruPenkman не будут блокировать сервер. это асинхронные операции, которые записываются как синхронизация. - person Inanc Gumus; 15.07.2014
comment
@EruPenkman, кто что сказал о сервере? Node можно использовать для множества вещей, помимо серверного кода - в частности, на нем написано множество инструментов тестирования. OP не указывает, что он пишет код для веб-сервера. - person Mark Amery; 26.02.2015
comment
Вы не хотите отвечать на вопрос "как?" говоря «нет!». - person tishma; 12.04.2016