Как мне дождаться нескольких асин c функций в NodeJS, прежде чем возвращать их все для обновления документа пожарного депо? - PullRequest
0 голосов
/ 25 апреля 2020

Я собираюсь упростить приведенный ниже код и добавлю комментарии по всему.

Общая идея заключается в том, что после того, как "лидер продаж" сохранен (звонок клиента) в моем приложении android (для Строительный концерт моего попса), я собираю сайт с pupeeteer, чтобы собрать некоторые данные об адресе. У меня уже все это работало, но (пока - успешно) я сохранял «внешний URL-адрес» с очищенного веб-сайта, но теперь я хотел бы просто взять внешний URL-адрес, получить изображение, загрузить его в свое хранилище Firestore Получите подписанный URL, а затем обновите документ Firestore с помощью этого «подписанного URL» (вместо внешнего URL). Кажется, все работает хорошо. Хорошо-я sh, но не в том порядке. Я получаю URL-адрес изображения и успешно сохраняю его в хранилище пожарного хранилища, но мой подписанный URL возвращается слишком поздно. Я просто озадачен обработкой обратных вызовов (или функций asyn c) здесь. Мне не обязательно нужен код (но я не откажусь от него! Ха-ха), может быть, просто общее руководство, как мне нужно организовать свой код. Я прочитал много информации о обратных вызовах, обещаниях и т. Д. c, но просто не могу обернуться и / или применить это к этому конкретному примеру.

Спасибо за любую помощь! Очень ценится!

exports.fetchData = functions.https.onCall(async (data, context) => {
    const urlLib = require("url");
    const pathLib = require("path"); 

    //Check for authentication
    if (!context.auth) { //not authed -> error
        throw new functions.https.HttpsError('failed-precondition', 'The function must be called ' +
            'while authenticated.');
    } else { //authed -> good to go

        var salesLeadId = data.salesLeadId; //grab leadID which is passed from my android app into this function (unique ID to identify the record I need to update)       

        try {    
            //Example URL
            let url = 'http://www.example.com'; //I left out code here where I build a custom URL etc.

            const browser = await puppeteer.launch(); 
            const [page] = await browser.pages();
            //Emulate Headless Chrome instance        
            await page.emulate({
                name: 'Desktop 1920x1080',
                userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36',
                viewport: {
                width: 1920,
                height: 1080
                }
            });
            //Opens Page, and waitws until loading is done
            await page.goto(url, { waitUntil: 'networkidle0' });

            //Read Data from web page and return as data object
            var data = await page.evaluate(() => {

                var scrapedPhoto = document.querySelector("#imgExamplePhoto").getAttribute('src'); //This is the external URL to the image
                // [...] grabbing other info here and adding it to "data"
                var accNo = "123456789"; //Example Data but in reality also fetched via document.queryselector
                var pId "12-44-66-88-88"; //Example Data but in reality also fetched via document.queryselector
                // etc...

                return { scrapedPhoto, accNo, pId }; //return all scraped data in var data

            });

            await browser.close();

            //below function is to grab the external URL, save it to Firestore Storage and return a Signed URL which I would then save with my lead document
            var uploadedPhotoUrl = await saveToStorage(data.scrapedPhoto); // THIS IS WHERE MY PROBLEM IS....the code keeps going. The function eventually returns the correct URL but way too late.

            //Firestore Document Reference for record to be updated
            let leadRef = admin.firestore().collection("sales_leads").doc(salesLeadId);

            //I've changed this in every way that I can think of by trial and error (i.e. tried chaining "thens", but unsuccessfully). I assume first I need to resolve the saveStorage function before proceeding to update my firestore document
            return leadRef.update({ //Here is where I'm going back to my Firestore Document and update it with this "new data"
                photo: uploadedPhotoUrl, //Problem: this is undefined because my code does NOT wait on "saveToStorage" above (Previously this was just the external "scrapedPhotoUrl" and thus worked fine. But instead of saving the external URL, I'm trying to save this image to firestore to avoid constant calls to their web page)
                pId: data.pID,
                accNo: data.accNo
            }).then(writeResult => {
                console.log(`Sales Lead updated with Data on: ${writeResult.writeTime.toDate()}`);
                return `Sales Lead updated with Data on: ${writeResult.writeTime.toDate()}`
            });        

        } catch (err) {
            console.error(err);
            return 'Error';
        }


    }
});

async function saveToStorage(fileUrl) {
    var storage = admin.storage();
    var fetch = require("node-fetch");
    var urlLib = require("url");
    var pathLib = require("path");
    //Get File Name from provided URL
    var parsed = urlLib.parse(fileUrl);
    var fileName = pathLib.basename(parsed.pathname);

    //Create Storage Reference with new File Name
    var bucket = storage.bucket('gs://myprojetname.appspot.com');
    var folderPath = 'sales/photos/';
    var internalFilePath = folderPath + fileName;
    var file = bucket.file(internalFilePath);

    //Fetch file from url
    return await fetch(fileUrl).then(res => {
      const contentType = res.headers.get('content-type');
      const writeStream = file.createWriteStream({
        metadata: {
          contentType
        }
      });
      return res.body.pipe(writeStream)
        .on('finish', () => {
          console.log('Image saved')
          return getDownloadURL(file); //so this eventually returns the corret URL, but by the time this "comes back" my main function has finished execution
        })
        .on('error', err => {
          writeStream.end();
          return console.error(err);
        });

    });


  }

//Get Signed Download URL from Firestore Storage. This works fine for me.
  function getDownloadURL(file) {     
    const config = {
        action: 'read',
        expires: '10-30-2050'
      };

    return file.getSignedUrl(config).then((downloadUrl) => {
      let result = downloadUrl[0];
      return result;
    }).catch(error => {
      console.error(error);
      return 'Error';
    });

  }




1 Ответ

0 голосов
/ 25 апреля 2020

Так что я думаю: «Я добираюсь туда». Я понял, что проблема, кажется, находится в моей функции "saveToStorage", как указано в моих результатах регистрации. (console.log был опубликован задолго до того, как результат был возвращен туда).

Теперь у меня, как мне кажется, есть все в правильном порядке.

функция saveToStorage =>

[...]
  return await fetch(fileUrl).then(res => {
    const contentType = res.headers.get('content-type');
    const writeStream = file.createWriteStream({
      metadata: {
        contentType
      }
    });
    let p = new Promise((resolve, reject) => {
      res.body.pipe(writeStream).on('finish', function() {
        resolve(file);
      });
      res.body.pipe(writeStream).on('error', function () {
        reject();
      });
    });

    return p.then(function(file) {
      console.log('Image saved')
      return getDownloadURL(file);
    });

  });
[...]

В эту функцию я добавил обещание, которое необходимо разрешить перед возвратом данных. Я получаю правильный URL-адрес и правильный (подписанный) URL-адрес хранилища записывается / обновляется в моем документе пожарного депо .... НО ...

Мои изображения пишутся только наполовину. Нижняя половина - серые пиксели. : головка царапается: (Раньше изображение было в порядке, но URL-адрес был возвращен слишком поздно. Теперь URL-адрес возвращается "вовремя", но изображение не кажется завершенным.)

Редактировать: Я собираюсь отметить это ответом и открыть новый вопрос с моей новой проблемой. Я считаю, что моя первоначальная проблема решена здесь. (Правка: завтра)

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