新聞中心
?如果能讓異步代碼正確工作,它可以大大簡化我們代碼。但是,處理這種額外的復(fù)雜性,特別是與可合一起,可能會令人困惑。這篇文章介紹了無等待的異步模式。這是一種在組合中編寫異步代碼的方法,而不像通常那樣令人頭疼。

創(chuàng)新互聯(lián)是專業(yè)的伊川網(wǎng)站建設(shè)公司,伊川接單;提供成都網(wǎng)站設(shè)計(jì)、做網(wǎng)站、成都外貿(mào)網(wǎng)站建設(shè)公司,網(wǎng)頁設(shè)計(jì),網(wǎng)站設(shè)計(jì),建網(wǎng)站,PHP網(wǎng)站建設(shè)等專業(yè)做網(wǎng)站服務(wù);采用PHP框架,可快速的進(jìn)行伊川網(wǎng)站開發(fā)網(wǎng)頁制作和功能擴(kuò)展;專業(yè)做搜索引擎喜愛的網(wǎng)站,專業(yè)的做網(wǎng)站團(tuán)隊(duì),希望更多企業(yè)前來合作!
無等待的異步
用組合API編寫異步行為有時會很麻煩。所有的異步代碼必須在任何反應(yīng)式代碼之后的設(shè)置函數(shù)的末端。如果你不這樣做,它可能會干擾你的反應(yīng)性。
當(dāng)setup函數(shù)運(yùn)行到一個await語句時,它將返回。一旦它返回,該組件就會被掛載,并且應(yīng)用程序會像往常一樣繼續(xù)執(zhí)行。任何在await之后定義的響應(yīng)式,無論是 computed、watcher,還是其他什么,都還沒有被初始化。
這意味著,一個在await之后定義的計(jì)算屬性一開始不會被模板使用。相反,只有在異步代碼完成,setup 函數(shù)完成執(zhí)行后,它才會存在。
然而,有一種方法可以編寫異步組件,可以在任何地方使用,而不需要這些麻煩。
const count = ref(0);
// 這種異步數(shù)據(jù)獲取不會干擾我們的響應(yīng)式
const { state } = useAsyncState(fetchData());
const doubleCount = computed(() => count * 2);
實(shí)現(xiàn)沒有等待的異步模式
為了實(shí)現(xiàn)這一模式,我們將同步地掛起所有的響應(yīng)式值。然后,每當(dāng)異步代碼完成后,這些值將被異步更新。
首先,我們需要把我們的狀態(tài)準(zhǔn)備好并返回。我們將用一個null的值來初始化,因?yàn)槲覀冞€不知道這個值是什么。
export default useMyAsyncComposable(promise) {
const state = ref(null);
return state;
}第二,我們創(chuàng)建一個方法,等待我們的 promise ,然后將結(jié)果設(shè)置為 state:
const execute = async () => {
state.value = await promise;
}每當(dāng)這個promise 返回時,它就會主動更新我們的state。
現(xiàn)在我們只需要把這個方法添加到組合中。
export default useMyAsyncComposable(promise) {
const state = ref(null);
// Add in the execute method...
const execute = async () => {
state.value = await promise;
}
// ...and execute it!
execute();
return state;
}我們在從useMyAsyncComposable方法返回之前調(diào)用了execute函數(shù)。然而,我們并沒有使用await關(guān)鍵字。
當(dāng)我們停止并等待execute方法中的 promise 時,執(zhí)行流立即返回到useMyAsyncComposable函數(shù)。然后它繼續(xù)執(zhí)行execute()語句并從可組合對象返回。
export default useMyAsyncComposable(promise) {
const state = ref(null);
const execute = async () => {
// 2. 等待 promise 執(zhí)行完成
state.value = await promise
// 5. 一段時間后...
// Promise 執(zhí)行完,state 更新
// execute 執(zhí)行完成
}
// 1. 執(zhí)行 `execute` 方法
execute();
// 3. await 將控制權(quán)返回到這一點(diǎn)上。
// 4. 返回 state 并繼續(xù)執(zhí)行 "setup" 方法
return state;
}promise在后臺執(zhí)行,因?yàn)槲覀儧]有等待它,所以它不會在setup函數(shù)中中斷流。我們可以將此可組合放置在任何地方,而不影響響應(yīng)性。
讓我們看看 VueUse 中一些組合是如何實(shí)現(xiàn)這種模式的。
useAsyncState
useAsyncState 可以讓我們在任何地方執(zhí)行任何異步方法,并獲得響應(yīng)性的更新結(jié)果。
const { state, isLoading } = useAsyncState(fetchData());在查看源代碼時,可以看到它實(shí)現(xiàn)了這種精確的模式,但具有更多的特性,并能更好地處理邊界情況。
下面是 useAsyncState 的一個簡化版:
export function useAsyncState(promise, initialState) {
const state = ref(initialState);
const isReady = ref(false);
const isLoading = ref(false);
const error = ref(undefined);
async function execute() {
error.value = undefined;
isReady.value = false;
isLoading.value = true;
try {
const data = await promise;
state.value = data;
isReady.value = true;
}
catch (e) {
error.value = e;
}
isLoading.value = false;
}
execute();
return {
state,
isReady,
isLoading,
error,
};
}這個可組合的系統(tǒng)還返回isReady,告訴我們數(shù)據(jù)何時被取走。我們還得到了isLoading和error,以跟蹤我們的加載和錯誤狀態(tài)。
現(xiàn)在來看看另一個可組合,我認(rèn)為它有一個迷人的實(shí)現(xiàn)方式。
useAsyncQueue
如果傳給useAsyncQueue一個 promise 函數(shù)數(shù)組,它會按順序執(zhí)行每個函數(shù)。所以,在開始下一個任務(wù)之前,會等待前一個任務(wù)的完成。為了使用更靈活,它上一個任務(wù)的結(jié)果作為輸入傳給下一個任務(wù)。
const { result } = useAsyncQueue([getFirstPromise, getSecondPromise]);下面是一個官網(wǎng)的例子:
const getFirstPromise = () => {
// Create our first promise
return new Promise((resolve) => {
setTimeout(() => {
resolve(1000);
}, 10);
});
};
const getSecondPromise = (result) => {
return new Promise((resolve) => {
setTimeout(() => {
resolve(1000 + result);
}, 20);
});
};
const { activeIndex, result } = useAsyncQueue([
getFirstPromise,
getSecondPromise
]);即使它在異步執(zhí)行代碼,我們也不需要使用await。即使在內(nèi)部,可組合的程序也不使用await。相反,我們在 "后臺"執(zhí)行這些 promise,并讓結(jié)果響應(yīng)式更新。
讓我們看看這個組合是如何工作的。
// 初始一些默認(rèn)值
const initialResult = Array.from(new Array(tasks.length), () => ({
state: promiseState.pending,
data: null,
});
// 將默認(rèn)值變成響應(yīng)式
const result = reactive(initialResult);
// 聲明一個響應(yīng)式的下標(biāo)
const activeIndex = ref(-1);
主要的功能是由一個reduce來支持的,它逐個處理每個功能
tasks.reduce((prev, curr) => {
return prev.then((prevRes) => {
if (result[activeIndex.value]?.state === promiseState.rejected && interrupt) {
onFinished();
return;
}
return curr(prevRes).then((currentRes) => {
updateResult(promiseState.fulfilled, currentRes);
activeIndex.value === tasks.length - 1 && onFinished();
return currentRes;
})
}).catch((e) => {
updateResult(promiseState.rejected, e);
onError();
return e;
})
}, Promise.resolve());Reduce 方法有點(diǎn)復(fù)雜,我們拆解一下,一個個看:
tasks.reduce((prev, curr) => {
// ...
}, Promise.resolve());然后,開始處理每個任務(wù)。通過在前一個promise基礎(chǔ)上鏈接一個.then來完成這個任務(wù)。如果promise 被拒絕,就提前中止并返回。
if (result[activeIndex.value]?.state === promiseState.rejected && interrupt) {
onFinished();
return;
}如果不提前終止,則執(zhí)行下一個任務(wù),并傳遞上一個 promise 的結(jié)果。我們還調(diào)用updateResult方法,將其添加到該組合返回的 result 數(shù)組中
return curr(prevRes).then((currentRes) => {
updateResult(promiseState.fulfilled, currentRes);
activeIndex.value === tasks.length - 1 && onFinished();
return currentRes;
});正如你所看到的,該可組合實(shí)現(xiàn)了Async Without Await模式,但該模式只是整個可組合的幾行。所以它不需要很多額外的工作,只要記住把它放在適當(dāng)?shù)奈恢?/p>
總結(jié)
如果我們使用Async Without Await模式,我們可以更容易地使用異步組合。這種模式可以讓我們把異步代碼放在我們想放的地方,而不用擔(dān)心破壞響應(yīng)應(yīng)性。
作者:Michael Thiessen
譯者:小智 來源:vuemastery
原文:https://www.vuemastery.com/blog/coding-btter-composables-1-of-5?
文章名稱:Vue3,用組合編寫更好的代碼:AsyncWithoutAwait模式
轉(zhuǎn)載源于:http://www.dlmjj.cn/article/dhgcohd.html


咨詢
建站咨詢
