我正在做我的第一個 React 網站,我需要幫助來撰寫異步 JavaScript 函式。在這里,我將用戶輸入檔案上傳到 firebase 存盤,然后向 API 發出發布請求以將資料存盤在資料庫中。但是,由于 firebase 上傳需要一些時間將資料上傳到其存盤,API 請求發生在上傳完成之前,因此資料不會上傳到資料庫。現在我知道我應該在這里使用 async await 關鍵字的承諾,但我不知道如何使用。如果有人可以提供幫助,我將不勝感激。提前致謝!
這是相關的代碼片段:
const save = (items) => {
items.forEach((item) => {
const fileName = new Date().getTime() item.label item.file.name;
const uploadTask = storage.ref(`/items/${fileName}`).put(item.file);
uploadTask.on(
"state_changed",
(snapshot) => {
const progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100;
console.log("Upload is" progress "% done.");
},
(err) => {
console.log(err)
},
() => {
storage.ref("items").child(fileName).getDownloadURL().then((url) => {
setSong((prev) => {
return { ...prev, [item.label]: url };
});
});
}
);
})
console.log(song)
axios.post("songs/create", song);
}
PS:這里,items 是來自用戶的輸入檔案的陣列,每個檔案都有一個標簽,它是 json 檔案中屬性的命名方式。setSong 是一個 useState 函式。這里 JSON 檔案已經包含其他用戶輸入(不是檔案),并且 setSong 方法用于將檔案的 firebase URL 附加到它。
uj5u.com熱心網友回復:
你必須等待所有檔案上傳然后你可以呼叫你的 API,為了做到這一點,你應該使用Promise.all等待決議所有檔案:
const save = items => {
Promise.all(
items.map(item => {
return new Promise(resolve => {
const fileName = new Date().getTime() item.label item.file.name
const uploadTask = storage.ref(`/items/${fileName}`).put(item.file)
uploadTask.on(
'state_changed',
snapshot => {
const progress =
(snapshot.bytesTransferred / snapshot.totalBytes) * 100
console.log('Upload is' progress '% done.')
},
err => {
console.log(err)
},
() => {
storage
.ref('items')
.child(fileName)
.getDownloadURL()
.then(url => {
setSong(prev => {
return { ...prev, [item.label]: url }
})
resolve({[item.label]: url})
})
}
)
})
})
).then((res) => {
const song = {}
res.forEach(item => {
return {
...song,
...item
}
})
axios.post('songs/create', song)
})
}
uj5u.com熱心網友回復:
解釋
函式和異步
Async/Await 可以在函式開始的任何地方實作。函式可以寫成以下形式:
function name(){};
function name() => {};
要撰寫異步函式,您將執行以下操作:
async function name(){};
盡管所有這些函式都被稱為函式,為了使函式在不呼叫它們的情況下運行,我們需要將它們轉換為IIFE或立即呼叫函式執行。如果您想創建一個函式并立即執行它,您可以將函式括在()'s 中并以();.
(function () {})();
如果我們簡化一下:
(() => {})();
實作異步會像這樣:
(async () => {})();
等待
的await運算子用于等待Promise,putingawait以運算式的前面使用許諾使得它等待的承諾。如果在不使用 promise 的運算式前面使用它,則它是多余的,您的代碼編輯器/IDE 會這樣說。
(async () => {
const str = await 'some string';
console.log(str);
})();
await這里是多余的,因為運算式'some string'與承諾無關,而是與字串有關。
(async () => {
const myPromise = new Promise((resolve, reject) =>
resolve('some string')
);
const str = await myPromise.then(x => console.log(x));
})();
await在這里正確使用,因為運算式myPromise與輸出字串的承諾有關。
執行
我不是 100% 確定 api 如何在承諾中作業,我建議你自己弄清楚,但這是我有根據的猜測:
const save = (items) => {
Promise.all(
items.map((item) => {
return new Promise(async (resolve) => {
const fileName = new Date().getTime() item.label item.file.name;
const uploadTask = await storage
.ref(`/items/${fileName}`)
.put(item.file);
await uploadTask.on(
"state_changed",
(snapshot) => {
const progress =
(snapshot.bytesTransferred / snapshot.totalBytes) * 100;
console.log("Upload is" progress "% done.");
},
(err) => {
console.log(err);
},
async () => {
await storage
.ref("items")
.child(fileName)
.getDownloadURL()
.then((url) => {
setSong((prev) => {
return { ...prev, [item.label]: url };
});
resolve({ [item.label]: url });
});
}
);
});
})
).then(async (res) => {
const song = {};
res.forEach((item) => {
return {
...song,
...item,
};
});
await axios.post("songs/create", song);
});
};
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/352328.html
標籤:javascript 反应 异步 异步等待 异步javascript
