Javascript оператор выполнения после завершения операторов выборки - PullRequest
0 голосов
/ 01 августа 2020

Здесь я конвертирую blob urls из массива с именем imgs[] в base64 data, а затем помещаю данные base 64 в массив с именем imgsPost[]. После того, как все данные base64 помещены в массив, я хочу использовать этот массив в функции.

let imgsPost = [];
let imgs = ["bloburl1", "bloburl2", "bloburl3", "bloburl4"];
for (let i = 0; i < imgs.length; i++) {
    fetch(imgs[i].src)
        .then(res => {
            if (!res.ok) {
                throw Error(res.statusText);
            }
            return res.blob();
        })
        .then(data => {
            let tempBlob = data;
            let reader = new FileReader();
            reader.readAsDataURL(tempBlob);
            reader.onloadend = function () {
                let base64data = reader.result;
                imgsPost.push(base64data);
            }
        })
        .catch(error => {
            console.error('Error:', error);
        })
}
        //After all execution
        foo($imgsPost);

Прямо сейчас функция сначала выполняется с пустым массивом. Все остальные коды работают.

Ответы [ 2 ]

2 голосов
/ 01 августа 2020

Это проблема асинхронизма. Вы говорите 4 раза выполнить код после результатов, затем вы выполняете foo($imgsPost); до результатов.

Решение, использующее Promise.all:

const imgs = [
    'https://www.gravatar.com/avatar/5ac4d13d84719bf7f11cfd9ba7e0b15b?s=32&d=identicon&r=PG&f=1',
    'https://www.gravatar.com/avatar/f1f3cf96ee354f414ec58c2824f80938?s=32&d=identicon&r=PG&f=1'
];

const promises = imgs.map(img => fetch(img)
    .then(res => {
        if (!res.ok) {
            throw Error(res.statusText);
        }
        return res.blob();
    })
    .then(data => {
        const reader = new FileReader();
        reader.readAsDataURL(data);
        return new Promise(resolve => reader.onloadend = () => resolve(reader));
    })
    .then(({ result }) => result)
);

const foo = console.log;

Promise.all(promises).then(foo).catch(error => {
    console.error('Error: ', error);
});

Вы также можете использовать синтаксис async / await, который предоставляет действительно полезный синтаксис c сахар вместо обещаний и делает код похожим на синхронный.

0 голосов
/ 01 августа 2020

Это потому, что foo($imgsPost) является синхронным и вызывается до того, как будут завершены запросы asyn c fetch. Вы можете попробовать создать кучу запросов на выборку и поместить их в массив и использовать Promise.all(), чтобы дождаться завершения всех запросов, прежде чем вызывать foo().

Я не уверен, что это опечатка или просто пример, но в вашем массиве imgs нет свойства .src.

const imgs = ["bloburl1", "bloburl2", "bloburl3", "bloburl4"];
const fetchRequests = imgs.map(img => {
    return fetch(img.src)
              .then(res => {
                 if (!res.ok) {
                    throw Error(res.statusText);
                 }
                 return res.blob();
                })
               .then(data => {
                  let tempBlob = data;
                  let reader = new FileReader();
                  reader.readAsDataURL(tempBlob);
                  reader.onloadend = function () {
                  return reader.result;            
                }
            })
            .catch(error => {
                console.error('Error:', error);
            })
        }

   Promise.all(fetchRequests).then(allRes => foo(allRes))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...