У меня есть небольшой код, написанный на JavaScript, который получает содержимое html-страниц, а затем обрабатывает их (искатель). проблема в том, что request вызывает асинхронное выполнение. Я попытался использовать Promises и async & await, но все равно получил ту же проблему с асинхронным выполнением, причина в том, что я хочу сканировать несколько страниц одновременно, чтобы перейти к следующей цели. Вот аналогичный код того, что у меня здесь:

const rootlink= 'https://jsonplaceholder.typicode.com/posts/';

async function f (){
    await f1()
    f3()
}

async function f1(){
    return new Promise(async (resolve,reject)=>{
        log('f1 start');
         for(let i=1;i<11;i++){
            await request(rootlink+i,(err, res,html)=>{
                if(!err && res.statusCode==200){
                    log('link '+i +' done');
                    resolve();
                }
                else reject()
            })
        }
    })
}

function f3(){
    console.log('f3')
}

f()

Результат должен быть следующим: f1 стартовая ссылка 1 выполненная ссылка 2 выполненная ссылка 3 выполненная ссылка 4 выполненная ссылка 5 выполненная ссылка 6 выполненная ссылка 7 выполненная ссылка 8 выполненная ссылка 9 выполненная ссылка 9 выполненная ссылка 10 выполненная f3

Вместо f1 стартовая ссылка 1 сделана f3 ссылка 2 сделана ссылка 3 сделана ссылка 4 сделана ссылка 5 сделана ссылка 6 сделана ссылка 7 сделана ссылка 8 сделана ссылка 8 сделана ссылка 9 сделана ссылка 10 выполнена

1
Imed Eddine BOUDRAA 28 Окт 2019 в 20:30

3 ответа

Лучший ответ

ПРИМЕЧАНИЕ. Я бы использовал изоморфный пакет извлечения, например node-fetch, чтобы создать код, который может использоваться в нескольких средах. Даже если вы не планируете использовать это в браузере, знакомство с API очень полезно для будущего использования. По крайней мере, эта идея позволила мне написать фрагмент кода, который вы действительно можете запустить в StackOverflow.

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

// const fetch = require('node-fetch')

const fetchData = (...args) => fetch(...args).then(r => {
  if (!r.ok) throw new Error('Error!')
  return r.json()
})

const getAllPostsAsync = (postIds) => Promise.all(
  postIds.map(postId => fetchData(`https://jsonplaceholder.typicode.com/posts/${postId}`))
)

;(async () => {
  const posts = await getAllPostsAsync([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
  
  // TODO: Your logic here, after waiting for all posts to load
  console.log(posts)
})()
1
BDawg 28 Окт 2019 в 18:30

Ответ на мой вопрос заключается в использовании синхронного запроса 'sync-request' от https://www.npmjs.com/package/sync-request

0
Imed Eddine BOUDRAA 28 Окт 2019 в 18:02

Учитывая, что вы хотите выполнять несколько асинхронных операций параллельно, вы на самом деле не хотите await их выполнять, поскольку это блокирует вашу функцию.

Во-первых, я бы сказал, что лучше найти библиотеку HTTP, которая использует обещания. Тот, который вы используете, имеет обратные вызовы, но я считаю, что проект request также имеет пакет request-promise, который намного проще в использовании.

Вот исправленная версия вашей функции f1, которая использует обещания более правильно. Обратите внимание, что это не распараллелено еще.

const request = require('request-promise');

async function f1(){
  log('f1 start');
  for(let i=1;i<11;i++){
     const res = await request(rootlink+i);
     if(res.statusCode==200){
        log('link '+i +' done');
     }
  }
}

Вот еще одна версия этой функции, за исключением того, что теперь она полностью распараллелена.

async function f1(){
  log('f1 start');
  const promises = [];
  for(let i=1;i<11;i++){
     promises.push(
       request(rootlink+i).then( (res) => {
         if(res.statusCode==200){
           log('link '+i +' done');
         }
       })
     );
  }

  await Promise.all(promises);
}

Это можно сделать несколько элегантнее, если разделить его на несколько функций:

async function f1(){
  log('f1 start');
  const promises = [];
  for(let i=1;i<11;i++){
     promises.push(checkLink(i));
  }

  await Promise.all(promises);
}

async function checkLink(i) {
  const res = await request(rootlink+i);
  if (res.statusCode==200){
     log('link '+i +' done');
  }
}
0
Evert 28 Окт 2019 в 17:39