Ваш улучшенный код в опубликованном вами ответе хорош, но его все же можно сделать более кратким и понятным:
- Обратите внимание, что асин c функции всегда возвращают Promises. По сути, вы просто оборачиваете каждое тело функции в Promise, чтобы они возвращали единицу, но это не нужно, если вы включаете в себя функцию asyn c.
- вместо использования логических значений для индикации состояния успеха / неудачи. Я вместо этого использовал отклоненные Обещания, так как он более идиоматический c в JavaScript и с помощью async / await вы можете написать это интуитивно «синхронно» (
throw
в асинхронной функции c приводит к отклонению возвращаемого Обещания ) - Когда вы можете вернуть значение, указывающее на успех, я настоятельно рекомендую сделать это - независимо от того, используете ли вы его на самом деле, это не имеет большого значения, но если вам это нужно, это может упростить существующий код.
- Вы можете использовать
try/catch
при использовании await
в качестве метода обработки await
ed Отклонения Promise, это делает код очень интуитивно понятным - Ненависть стиля: использование точек с запятой несовместимо. Либо точка с запятой, либо точка с запятой не годится, но вы должны придерживаться одной или другой. Это улучшает читабельность, и если кто-то еще коснется вашего кода, у него не возникнет вопросов о том, когда использовать точку с запятой.
async loadData(): Promise<void> {
try {
return await this.loadFromLocalStorage(); //await this one to catch rejections
} catch(e) {
console.log(e.message); //handle error
return this.loadFromApi(); //await or don't await this one, same result
}
}
async loadFromLocalStorage() : Promise<Pilot[]> {
if( !this.isSupported(() => localStorage) ) throw new Error("Not Supported");
//if JSON.parse errors, the promise will also convert the exception to a rejection
data = JSON.parse( localStorage.getItem('metadata') );
if( !data || !data.date ) throw new Error("No Data");
//this function returns a promise resolving with whatever `setData` resolves with
//or rejects if `setData` rejects
return this.setData(data, false);
}
//this one still needs to return a promise as it wraps a .subscribe()
loadFromApi() : Promise<(Pilot|void)[]> {
return new Promise((resolve, reject) => {
this.http.get<{date?:string,ddi?:number,stoff?:number}>(this.apiUrl+'meta.json')
.subscribe( data => {
resolve(this.setData(data, true)); //resolve with the data
},
reject); //if there's an error, just reject with the error
});
}
async setData(data, saveToLocal: boolean) : Promise<(Pilot|void)[]> {
let promises: Promise<Pilot|void>[] = [];
if (data.ddi) {
promises.push( this.pilotService.getById(data.ddi).then(ddi => this.ddi = ddi) );
}
//Promise.all will reject if any one of the inner promises rejects
//To circumvent this, add a .catch() to the inner promises
return Promise.all(promises);
}
Этот код соответствует более идиоматическому c использованию Promises и асинхронно / жду. Каждая функция либо разрешает со значимым значением в случае успеха, либо отклоняет со значительной ошибкой, если по какой-либо причине происходит сбой.
Из-за асинхронности / ожидания все ошибки также приводят к тому, что отклонение «заполняет» стек до самого вызывающего, т. Е. Если что-то пойдет не так в loadFromApi()
Обещание отклонит с ошибкой, которая затем приводит к отклонению loadData()
с той же самой ошибкой, открывая ее для функции, вызвавшей loadData()
, и позволяя вам инкапсулировать обработку ошибок для этого API данных (любые ошибки, вызванные любой внутренней функцией, могут " пузыря "до точки входа loadData()
и будет обрабатываться, как вы будете sh)