Как вызвать функцию синхронно

const filesHandler = (_files: File[]) => {

        for (let i = 0; i < _files.length; i++) {
            let file = _files[i]

            if (file?.type.startsWith("image/")) {
                let name = file.name.split('.')[0]
                postPartNames[i] = name;
                postPartFiles[i] = file;
                let reader = new FileReader();

                reader.readAsDataURL(file)
                reader.onload = () => {
                    postPartSrc[i] = reader.result  
                }
            }
        }
}

У меня есть вот такая функция, мне надо, чтобы после того как FileReader Загрузит все файлы, у меня запустилась другая функция, как мне это сделать ?


Ответы (2 шт):

Автор решения: qwabra

как бы я написал. (конечно же ответ на вопрос это второй пример)

песочница там

как мне кажется, в обоих случаях стоит обратить внимание на обработку reader.onerror

module ORIGIN {
    export class Data {
        constructor(
            public name: string,
            public file: File,
            public result?: string | ArrayBuffer | null,
        ) { }
    }
    export const postPart = new Map<number, Data>()
    export const filesHandler = (fileList: File[]) => {
        for (let i = 0; i < fileList.length; i++) {
            const file = fileList[i]
            if (file?.type.startsWith("image/")) foo(file, i)
        }
    }

    function foo(file: File, i: number) {
        const name = file.name.split('.')[0]
        const reader = new FileReader();
        reader.readAsDataURL(file)
        reader.onload = () => {
            postPart.set(i, new Data(name, file, reader.result))
        }
        reader.onerror = () => {
            // TODO:
            postPart.set(i, new Data(name, file, null))
        }
    }
}
module Q1 {
    class Data {
        constructor(
            public name: string,
            public file: File,
            public result?: string | ArrayBuffer | null,
        ) { }
        static genPromise = (data: Data) => {
            return new Promise<Data>((resolve, reject) => {
                if (data.result) {
                    resolve(data)
                } else {
                    const reader = new FileReader();
                    reader.onload = onload
                    reader.onerror = onerror
                    reader.readAsDataURL(data.file)

                    function onload(this: FileReader, ev: ProgressEvent<FileReader>) {
                        data.result = reader.result
                        resolve(data)
                    }
                    function onerror(this: FileReader, ev: ProgressEvent<FileReader>) {
                        reject()
                    }
                }
            })
        }
    }

    export const filesFilter = (fileList: File[], key: string) =>
        fileList.filter(file => file?.type.startsWith(key))

    export const filesHandlerPromise = (fileList: File[]) =>
        fileList.map(file => {
            const name = file.name.split('.')[0]
            return Data.genPromise(new Data(name, file))
        })

    export const filesHandler = (fileList: File[]) =>
        fileList.map(file => {
            const name = file.name.split('.')[0]
            return new Data(name, file)
        })
}

{//test
    const fileList: File[] = null as any
    {//ex1
        Promise
            .all(
                Q1.filesHandlerPromise(Q1.filesFilter(fileList, 'image/'))
            )
            .then(dataList => {
                dataList.forEach(data => {
                    console.log(data.name)
                })
            })
    }
    {//ex2
        void async function () {
            const dataList = await Promise.all(Q1.filesHandlerPromise(Q1.filesFilter(fileList, 'image/')))

            dataList.forEach(data => {
                console.log(data.name)
            })
        }()
    }
}
→ Ссылка
Автор решения: mego4iter

Можно решить через async/await и Promise

const filesHandler = (files: File[]): Promise<any> => {
  const out = files
    .filter(f => f?.type.startsWith("image/"))
    .map((f) => {
      let name = f.name.split('.')[0]

      const fileResult = {
        name, 
        file: f,
        result: null,
        error: null,
      };
      
      return new Promise((resolve, reject) => {
        let reader = new FileReader();
        reader.readAsDataURL(f)
        reader.onload = () => {
          fileResult.result = reader.result;
          resolve(fileResult);
        };
        reader.onerror = (err) => {
          fileResult.error = err;
          reject(fileResult);
        };
      });
    });

  return Promise.all(out);
}

// Использовать
const loadedFiles = await filesHandler(files);
→ Ссылка