[英]How can I wait for all dynamic nested promises to end?
我有以下代碼:
getContent() {
fetch(this.url)
.then((response) => response.text())
.then((data) => {
let jsonData = JSON.parse(data);
for (let i=0; i<jsonData.results.length; i++) {
this.fetchPokemon(jsonData.results[i].url)
.then(() => console.log("end"));
}
console.log(calls);
})
.catch((error) => console.log(error));
}
fetchPokemon(url) {
return new Promise((resolve) => {
fetch(url)
.then((response) => response.text())
.then((data) => {
let jsonData = JSON.parse(data);
let types = new Array();
for (let i=0; i<jsonData.types.length; i++) {
types.push(jsonData.types[i].type.name);
}
this.pokemons.push(new Pokemon(jsonData.name, types, jsonData.weight, jsonData.sprites.front_default));
resolve();
})
.catch((error) => console.log(error));
});
}
這是我正在處理的 JS class 中的兩個函數。 如您所見,function getContent()
執行fetch()
並從 API 獲取一些信息。這些信息包含更多 URL,我也想在其中獲取一些信息,因此我放置了一個for
循環來執行第二個 function fetchPokemon(url)
這將再次調用 API 以獲取一些其他信息。
我正在努力了解如何從getContent()
中檢測到循環中的所有Promises
都得到正確解析,以便我可以繼續執行其他功能。 感覺Promise.all
可以幫忙,但是沒成功。
我怎樣才能做到這一點?
促進可重用性
盡量不要在課堂上投入太多。 功能應該圍繞可移植性進行設計,使它們更容易重用和測試。
function getJson(url) {
return fetch(url)
.then((response) => response.text())
.then((data) => JSON.parse(data))
}
現在 class 可以保持精簡,程序中需要 JSON 的任何其他部分也可以從分離的 function 中受益 -
class MyClass {
constructor () {
// ...
}
async getContent () {
const data = await getJson(this.url)
// ...
}
}
轉到fetchPokemon
,看看那個,我們需要更多的 JSON! 獲取單個 Pokemon 是一項簡單的任務,只需要輸入url
並返回一個新的Pokemon
。 沒有理由將它與 class 邏輯糾纏在一起——
async function fetchPokemon(url) {
const { name, types, weight, sprites } = await getJson(url)
return new Pokemon(
name,
types.map(t => t.name),
weight,
sprites.front_default
)
}
現在我們可以完成 class 的getContent
方法 -
class MyClass {
constructor () {
// ...
}
async getContent () {
const { results } = await getJson(this.url)
return Promise.all(results.map(item => fetchPokemon(item.url)))
}
}
揭開面紗
現在我們可以清楚地看到getContent
只不過是一個簡單的 function 請求多個pokemon。 如果僅僅是這樣,我也會將其設為通用 function -
async function fetchAllPokemon(url) {
const { results } = await getJson(url)
return Promise.all(results.map(item => fetchPokemon(item.url)))
}
對 class 的需求基本上已經消失。 您沒有共享它的其他部分,但您的程序已簡化為三 (3) 個函數getJson
、 fetchPokemon
和fetchAllPokemon
所有這些都是可重用且易於測試的,以及一個非常簡單的MyClass
包裝器 -
function getJson(...) { ... }
async function fetchPokemon(...) { ... }
async function fetchAllPokemon(...) { ... }
class MyClass {
constructor() {
// ...
}
getContent() {
return fetchAllPokemon(this.url)
}
}
促進多功能性
我還應該提到getJson
可以簡化,因為fetch
響應包含一個.json
方法。 為了使其更有用,您可以添加第二個options
參數 -
function getJson(url, options = {}) {
return fetch(url, options).then(res => res.json())
}
不要吞下錯誤
最后,不要在通用函數或 class 方法上附加.catch
錯誤處理程序。 錯誤會自動冒出並為調用者保留做更有意義的事情的機會 -
fetchAllPokemon(someUrl)
.then(displayResult)
.catch(handleError)
或者,如果您仍計划使用 class -
const foobar = new MyClass(...)
foobar
.getContent()
.then(displayResult)
.catch(handlerError)
縮小
過去,類用於通過封裝邏輯、變量和方法來組織程序。 通常 class 結構會導致難以管理和難以測試的層次結構。 現在有了通過import
和export
的模塊支持,你可以編寫“扁平化”的程序,功能和組件可以以靈活的方式組合。 考慮使用我們上面編寫的函數的這個 ExpressJS 示例 -
import express from "express"
import { fetchPokemon, fetchAllPokemon } from "./api.js"
app.get("/pokemon", (res, res, next) => {
fetchAllPokemon(`https://someurl/`)
.then(data => res.json(data))
.then(_ => next())
.catch(err => next(err))
}
app.get("/pokemon/:id",(req,res,next)=> {
fetchPokemon(`https://someurl/${req.params.id}`)
.then(data => res.json(data))
.then(_ => next())
.catch(err => next(err))
}
或者使用async
和await
更好,因為錯誤會自動冒出來 -
import express from "express"
import { fetchPokemon, fetchAllPokemon } from "./api.js"
app.get("/pokemon", async (res, res) => {
const data = await fetchAllPokemon(`https://someurl/`)
res.json(data)
}
app.get("/pokemon/:id", async (res, res) => {
const data = await fetchPokemon(`https://someurl/${req.params.id}`)
res.json(data)
}
嘗試像這樣使用Promise.all
:
getContent() {
fetch(this.url)
.then((response) => response.text())
.then((data) => {
let jsonData = JSON.parse(data);
const promises = [];
for (let i=0; i<jsonData.results.length; i++) {
promises.push(this.fetchPokemon(jsonData.results[i].url));
}
return Promise.all(promises);
})
.then((results) => {
console.log(results);
})
.catch((error) => console.log(error));
}
所以基本上你只需將所有 Promise 推送到數組,然后應用Promise.all
來等待它們解決。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.