Почему «не дождаться» ожидания завершения запроса ax ios? - PullRequest
1 голос
/ 24 февраля 2020

Я попытался прочитать HTTP-ответ с помощью ax ios и проанализировать JSON в потоковом режиме с помощью stream-json`, чтобы я мог полностью подогнать свою базу данных по требованию. Это работает хорошо, но если я попытаюсь закрыть соединение с базой данных , все будет прервано, потому что соединение будет закрыто слишком рано. Проблема в том, что await не ожидает завершения функции extract_coins (даже если она возвращает обещание) и закрытия подключения к базе данных в окончательной области.

const main = async() => {
   const dbcfg = config.get('db.coins');
   const db = await coins_db_configure(dbcfg);
   try {
      console.log('Connected to the database and created coins table!');

      await extract_coins('some_url_which_gives_correct_json', coins_emitter);
   }
   catch(e){
      console.error(e);
   }
   finally {
      await db.close();
   }
   };

main();

extract_coins:

module.exports = async function extract_coins(url, emitter){
    return await axios({
        method: 'get',
        url: url,
        responseType: 'stream'
    }).then((res) => {
        const pipeline = chain([
            res.data,
            parser(),
            pick({filter: 'data'}),
            streamArray()
        ]);
        pipeline.on('data', data => {
            emitter.emit('coin_extracted', data.value);
        });
        pipeline.on('end', () => console.log("All the coins were successfully passed!"));
    });
};

Ответы [ 2 ]

2 голосов
/ 24 февраля 2020

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

Ваш await действительно ожидает обещания для разрешения, но ваш then обратный вызов возвращает undefined, и, таким образом, решение обещания выполняется в тот самый момент, задолго до end событие транслируется.

Поэтому измените это:

then((res) => {
    const pipeline = chain([
        res.data,
        parser(),
        pick({filter: 'data'}),
        streamArray()
    ]);
    pipeline.on('data', data => {
        emitter.emit('coin_extracted', data.value);
    });
    pipeline.on('end', () => console.log("All the coins were successfully passed!"));
});

На это:

then((res) => new Promise((resolve) => {
    const pipeline = chain([
        res.data,
        parser(),
        pick({filter: 'data'}),
        streamArray()
    ]);
    pipeline.on('data', data => {
        emitter.emit('coin_extracted', data.value);
    });
    pipeline.on('end', () => {
        console.log("All the coins were successfully passed!");
        resolve();
    });
}));
0 голосов
/ 25 февраля 2020

На самом деле, вы использовали ES6 + способом, но не обычным способом, это вызывает эту проблему, но, безусловно, использование await вместе с then является именно ошибкой, вы должны написать их так, как показано ниже коды:

const main = async () => {
   try {
     const dbcfg = config.get('db.coins');
     const db = await coins_db_configure(dbcfg);
     console.log('Connected to the database and created coins table!');
     await extract_coins('some_url_which_gives_correct_json', coins_emitter);

   } catch (e) {
      console.error(e);

   } finally {
      await db.close();

   }
};

main();

Как видите, я поместил все коды в блок try, потому что использование async/await означает, что мы притворяемся, что пишем код syn c, но фактически это async, поэтому мы должны поместить все коды, особенно асинхронные строки, в блок try. после помещения их в блок try только из-за флага async, стоящего за () JavaScript, интерпретатор ожидает завершения каждой строки до sh, если в каждой строке есть ошибка, следующие строки не будут выполняться, и интерпретатор попадет в Блок catch, наконец, работает во всех случаях, как вы сейчас.

Хорошо, теперь вернемся к основной проблеме, функция extract_coins:

export default (async function extract_coins(url, emitter) {
  try {
    const res = await axios({
      method: 'get',
      url: url,
      responseType: 'stream'
    });
    const pipeline = chain([
      res.data,
      parser(),
      pick({filter: 'data'}),
      streamArray()
    ]);
    await pipeline.on('data', data => {
      emitter.emit('coin_extracted', data.value);
    });
    await pipeline.on('end', () => console.log("All the coins were successfully passed!"));
    // HERE: return what you want

  } catch (e) {
    throw e;

  }

});

Это является причиной проблемы, вы должны передать обещание функции extract_coins с новым методом EcmaScript, не используя функции обратного вызова.

Если я зайду на вашем месте, я напишу extract_coins, как показано ниже:

const extract_coins = async (url, emitter) => {
  try {
    const res = await axios({
      method: 'get',
      url: url,
      responseType: 'stream'
    });
    const pipeline = chain([
      res.data,
      parser(),
      pick({filter: 'data'}),
      streamArray()
    ]);
    await pipeline.on('data', data => {
      emitter.emit('coin_extracted', data.value);
    });
    await pipeline.on('end', () => console.log("All the coins were successfully passed!"));
    // HERE: return what you want

  } catch (e) {
    throw e;

  }

};

export default extract_coins;
...