Как выполнить код, ожидая завершения промиса



У меня есть экспресс-приложение, в котором есть функция генератора, которой требуется прибл. 5 минут на обработку большого количества данных. К сожалению, я не могу оптимизировать эту функцию.
Express автоматически тайм-аут через 2 минуты, и я не не хотите изменить это только для этой конкретной функции. Я подумал, что, возможно, если бы я периодически делал res.write() вызов, правило двух минут не применялось.

Мой вопрос:
Как я могу выполнять res.write('Something') каждые X секунд, ожидая завершения другой функции?

Я хочу, чтобы он делал что-то вроде следующего, надеюсь, вы уловили идею.

    function main() {
      co(function* () {
        const something = yield promise(); // function that needs a lot of time
        const doWhileWaiting = setTimeout(() => {
          if (!something) {
            // Print this while waiting for the value of something
            console.log('Waiting for something ... ');
          } else {
            console.log(something);
            clearInterval(doWhileWaiting);
          }
        }, 5000);
      });
    }

person Felix    schedule 20.03.2017    source источник
comment
что-то вроде этого? stackoverflow.com/questions/9751711/   -  person Kevin B    schedule 20.03.2017
comment
Вы хотите, чтобы пользователь ждал целых пять минут? Вы можете отправить ответ типа Спасибо, ваши данные будут готовы через пять минут. и предоставьте уведомление через веб-перехватчик, веб-сокет, push-уведомление и т. д. или просто дайте им ссылку, где они могут проверить, когда оно будет готово.   -  person Explosion Pills    schedule 20.03.2017
comment
Это для приложения, в конечном итоге сервер будет выполнять скрипт один раз в день, который вызывает эту функцию. Проблема в том, что из-за доходности все после «что-то» не будет выполняться, пока не завершится. Есть ли способ выполнить его в фоновом режиме и получить уведомление, когда он будет завершен?   -  person Felix    schedule 21.03.2017
comment
Я думаю, вам нужен дочерний процесс...   -  person stdob--    schedule 21.03.2017
comment
Что именно вы подразумеваете под сервер будет выполнять скрипт один раз в день? Вы имеете в виду, что другой сервер делает HTTP-запрос к вашей конечной точке? В противном случае я не вижу, какое отношение к этому имеет экспресс.   -  person Bergi    schedule 21.03.2017


Ответы (2)


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

Как вы говорите, он выполняется один раз в день, вы можете запустить cronjob другой процесс. Если вам нужно связаться с вашим процессом API, вы можете посмотреть дочерние процессы. https://nodejs.org/api/child_process.html

person Johannes Merz    schedule 20.03.2017

Это не очень сложно реализовать:

const secret = Symbol();
const delay = ms => new Promise(r => setTimeout(() => r(secret), ms));

async waitFor(promise) {
    while(true) {
        const racer = await Promise.race(promise, delay(1));
        if(racer !== secret) return; // our promise won!
        await delay(100);
   }
}

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

async waitFor(promise, action) {
    while(true) {
        const racer = await Promise.race(promise, delay(1));
        if(racer !== secret) return; // our promise won!
        await action(); // support passing a promise action.
        await delay(100);
   }
}

// will write to `res` every 100 ms while `yourPromise is not resolved.
waitFor(yourPromise, () => res.write("...")); 

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

person Benjamin Gruenbaum    schedule 20.03.2017