【问题标题】:Firebase Cloud Functions: Promise not resolvingFirebase Cloud Functions:承诺无法解决
【发布时间】:2019-07-21 06:04:48
【问题描述】:

我的云函数中的特定调用出现了一些问题,似乎无法正确解决。

这是不想解析的代码:

console.log('Getting Search Patterns');
let searchPatterns: FirebaseFirestore.QuerySnapshot;
  try {
    searchPatterns = await admin
      .firestore()
      .collection('FYP_LOCATIONS')
      .get();
    } catch (error) {
      console.error(error);
    }
 console.log(`Search Patterns Received: ${searchPatterns}`);

日志:

正如您在日志中看到的,我的函数一直运行到 try 块之前的控制台日志,然后停止直到函数超时。我不确定是什么导致了这个问题。

编辑:我通过将云函数中的每个不同部分分离为我可以调用的单独函数来重新格式化我的代码;生成的 getSearchTerms() 函数如下:

async function getSearchTerms(): Promise<FirebaseFirestore.DocumentData[]> {
  try {
    const snapshot = await admin
      .firestore()
      .collection('FYP_LOCATIONS')
      .get();
    console.log('Get Returned');
    return snapshot.docs.map(doc => doc.data());
  } catch (e) {
    console.error(e);
    return [];
  }
}

这还是在函数执行的同一点停止,完整的函数在这里,这个已经更新到最新版本了:

import * as functions from 'firebase-functions';
import * as admin from 'firebase-admin';
import * as path from 'path';
import * as WordExtractor from 'word-extractor';
import * as textract from 'textract';
import suffixArray from './suffixArray';

// interface Location {
//   lid: string;
//   location_name: string;
//   location_type: string;
//   sentimental_value: number;
// }

// interface Context {
//   lid: string;
//   context_string: string;
//   fid: string;
// }

export const processFile = functions.storage.object().onFinalize(async file => {
  const serviceAccount = require(__dirname + '/../config/serviceAccount.json');

  admin.initializeApp({
    credential: admin.credential.cert(serviceAccount),
    databaseURL: 'https://fyp-alex.firebaseio.com',
  });

  const firestore = admin.firestore();

  const fileBucket: string = file.bucket;
  const filePath: string = file.name;
  const fileDet: string = path.basename(filePath);
  const fileNameSplit: string[] = fileDet.split('.');
  const fileExt: string = fileNameSplit.pop();
  const fileName: string = fileNameSplit.join('.');
  const bucket = admin.storage().bucket(fileBucket);
  const fileRef = bucket.file(filePath);
  const _path: string = `/tmp/${fileName}.${fileExt}`;
  console.log(`File path ${filePath}`);
  console.log('Getting Download URL');
  try {
    console.log(`Downloading to: ${_path}`);
    await fileRef.download({ destination: _path });
    console.log('File Saved');
    console.log(`Getting Details: ${_path}`);
    const text: string = await getText(_path, fileExt);
    console.log(`Processing: ${fileName}`);
    console.log('Creating Suffix Array');
    const suffix_array = suffixArray(text);
    console.log(`Suffix Array Created: ${suffix_array}`);
    console.log('Getting Search Patterns');
    const searchTerms: FirebaseFirestore.DocumentData[] = await getSearchTerms();
    console.log('Search Patterns Received');
    const promises = [];
    const allContexts: Object[] = [];
    for (const searchDoc of searchTerms) {
      const searchTerm = searchDoc.location_name.toLowerCase();
      console.log(searchTerm);
      const matchedIndexes = search(text, searchTerm, suffix_array);
      const contexts = createContexts(matchedIndexes, searchDoc, text, fileName);
      allContexts.concat(contexts);
    }
    for (const context of allContexts) {
      const p = admin
        .firestore()
        .collection('FYP_CONTEXTS')
        .add(context);
      promises.push(p);
    }
    await Promise.all(promises);
    const data = {
      processed: 1,
    };
    return firestore.doc(`FYP_FILES/${fileName}`).update(data);
  } catch (e) {
    console.error(e);
    const data = {
      processed: 2,
    };
    return firestore.doc(`FYP_FILES/${fileName}`).update(data);
  }
});

async function getText(_path: string, fileExt: string) {
  let text: string = '';

  switch (fileExt) {
    case 'docx':
    case 'doc':
      const extractor = new WordExtractor();
      const extracted = await extractor.extract(_path);
      text = extracted.getBody();
      break;
    case 'pdf':
      break;
    case 'txt':
      textract.fromFileWithPath(_path, function(extractedError: any, string: string) {
        if (extractedError) {
          console.error(extractedError);
        }
        if (string !== null) {
          text = string;
        }
      });
      break;
    default:
      console.log('Unsupported File Type');
  }
  return text;
}

async function getSearchTerms(): Promise<FirebaseFirestore.DocumentData[]> {
  try {
    const snapshot = await admin
      .firestore()
      .collection('FYP_LOCATIONS')
      .get();
    console.log('Get Returned');
    return snapshot.docs.map(doc => doc.data());
  } catch (e) {
    console.error(e);
    return [];
  }
}

function createContexts(
  matchedIndexes: number[],
  searchDoc: FirebaseFirestore.DocumentData,
  text: string,
  fileName: string
) {
  console.log('Creating Contexts');
  const contexts = [];
  const searchTerm = searchDoc.location_name.toLowerCase();
  for (const index of matchedIndexes) {
    let left = index - 25;
    let right = index + searchTerm.length + 25;
    if (left < 0) {
      left = 0;
    }
    if (right > text.length) {
      right = text.length;
    }
    const context = text.substring(left, right);
    contexts.push({
      lid: searchDoc.lid,
      context_string: context,
      fid: fileName,
    });
  }
  return contexts;
}

function search(text: string, searchTerm: string, suffix_array: number[]) {
  console.log(`Beginning search for: ${searchTerm}`);
  let start = 0;
  let end = suffix_array.length;
  const matchedIndexes: Array<number> = [];

  while (start < end) {
    const mid: number = (end - 1) / 2;
    const index: number = suffix_array[mid];
    const finalIndex: number = index + searchTerm.length;
    if (finalIndex <= text.length) {
      const substring: string = text.substring(index, finalIndex);
      const match: number = searchTerm.localeCompare(substring);

      if (match === 0) {
        console.log(`Match Found at Index: ${index}`);
        matchedIndexes.push(index);
      } else if (match < 0) {
        end = mid;
      } else if (match > 0) {
        start = mid;
      }
      console.log(matchedIndexes);
    }
  }

  if (matchedIndexes.length === 0) {
    console.log(`No matches found for search term: ${searchTerm}`);
  }

  return matchedIndexes;
}

希望完整的函数能提供更多的上下文。

我已经看过 Doug 的视频几次,但我仍然反对这一点,我确实注意到删除似乎失败的等待(如一起删除承诺)似乎会导致更早的等待失败.这表明它是稍后在函数中的承诺的问题,但我无法终生找到问题,我会继续尝试,但希望能提供一些有用的上下文。

【问题讨论】:

  • 显然你没有返回异步get()操作返回的承诺。我建议您观看 Firebase 视频系列中关于“JavaScript Promises”的 3 个视频:firebase.google.com/docs/functions/video-series,其中详细解释了为什么这是一个关键点。
  • 但是因为我在等待 get() 它不只是返回快照吗?
  • 我添加了更多代码来帮助提供更多有关问题的背景信息。
  • 您的两个 for 循环中没有 return。您可能应该重新组织这部分代码,以便正确返回承诺并正确链接这些承诺。同样,Doug Stevenson 的视频可能会有很大帮助。
  • 我已经重新组织了 for 循环并让它们返回了一些值,但现在我仍然得到相同的结果,你能发现其他可能有问题的地方吗?我看过 Doug 的视频几次,这对我有很大帮助,但我仍然没有发现问题所在。

标签: javascript firebase promise google-cloud-firestore google-cloud-functions


【解决方案1】:

您不会让函数知道异步操作何时完成。 我猜你想将所有异步操作收集到一个数组中,并等待所有操作完成后再让函数退出。

(Doug 的那些 youtube 视频,在上面的 cmets 中提到非常好,并且更彻底地解释了为什么

即。

const requests = [];
const things = [1,2,3];
for (let index = 0; index < things.length; index++) {
  const element = things[index];
  const promise = firebase.firestore().push(element);
  requests.push(promise);
}

return Promise.all(requests);

【讨论】:

  • 我已经尝试这样做来整理 promise 调用,但我仍然遇到同样的问题。我已经更新了问题中的代码,我确实觉得我的承诺有问题,但我不确定。
猜你喜欢
  • 2017-09-01
  • 1970-01-01
  • 1970-01-01
  • 2020-04-22
  • 2017-08-31
  • 2014-01-25
  • 1970-01-01
  • 1970-01-01
  • 2020-02-18
相关资源
最近更新 更多