大家好,
如果想要防止使用者連續按button傳送request的情況,
所以程式碼如下:
const button = (function (clicked) {
return () => {
if (!clicked) return;
clicked = false
let postData = new FormData()
postData.append('key', 'this is value')
try {
fetch('http://XXXX'.postData)
.then(res => res.json())
.then(data => { })
.catch(() => { })
.finally(() => {
clicked = true
})
} catch {
clicked = true
}
}
}(true))
為了精簡程式碼,所以想將click once的功能做成一個套件,可重複使用,大致如下,
fn要能適用於,同步與異步的function。
const fn = (anyFunction = () => { }) => {
return new Promise((resolve, reject) => {
try {
anyFunction() //(a)
resolve() //(b)
} catch {
reject()
}
})
}
const clickOnceBtn = (anyFunction = () => { }) => {
(function (isClicked) {
return async () => {
if (!isClicked) return;
isClicked = false
await fn(anyFunction) //(c)
isClicked = true //(d)
}
}(true))
}
想要應用的方式如下,
const theFetch = ()=>{
let postData = new FormData()
postData.append('key', 'this is value')
fetch('http://XXXX',postData)
.then(res => res.json())
.then(data => { })
.catch(() => { })
}
const button = clickOnceBtn(theFetch) //最後將button綁到onclick事件
目前卡在(c)還沒執行完,就執行(d)
原因是(b)在(a)還沒執行完就先回傳。
請問該怎麼修改比較好呢?
感謝
-----【解決方法】------
(1)放棄anyFunction帶入fn的作法,因為還需判斷是否有axios或fetch或promise。
(2)clickOnceBtn的架構維持不變。
const clickOnceBtn = (anyFunction) => {
return (function (isClicked) {
return async () => {
if (isClicked) return;
isClicked = true
try {
await anyFunction()
//原本是 await fn(anyFunction)
} finally {
isClicked = false
}
}
}(false))
}
(3)自行判斷function。
如果是普通function,const noFetch = ()=>console.log('')
。
如果有promise就必須這樣,
const theFetch = () => {
return new Promise((resolve, reject) => {
try {
let postData = new FormData()
postData.append('key', 'this is value')
fetch('http://XXX', postData)
.then(res => res.json())
.then(data => { })
.catch(() => { })
.finally(() => resolve()) //resolve改到這裡
} catch {
reject()
}
})
}
(4)使用
const button1 = clickOnceBtn(theFetch)
const button2 = clickOnceBtn(noFetch)
提供大家參考,
也感謝大大們幫忙提供意見。
ps.忙了老半天,其實也才節省了三行。好像沒什麼必要這樣做
要解決這個問題,你可以將resolve延遲到async function完成執行後再呼叫。
以下是修改後的程式碼:
const fn = (anyFunction = () => { }) => {
return new Promise((resolve, reject) => {
try {
const result = anyFunction(); // (a)
if (result instanceof Promise) {
result.then(() => {
resolve(); // (b)
}).catch(() => {
reject();
});
} else {
resolve(); // (b)
}
} catch {
reject();
}
});
};
const clickOnceBtn = (anyFunction = () => { }) => {
(function (isClicked) {
return async () => {
if (!isClicked) return;
isClicked = false;
try {
await fn(anyFunction); // (c)
} finally {
isClicked = true; // (d)
}
};
}(true));
};
這樣就可以確保在(async function (a)中的所有代碼執行完畢後,才會呼叫resolve (b)。
function triggerOnce(handler) {
let busy = false;
return async (event) => {
if (busy) {
return;
}
busy = true;
try {
await handler(event);
} finally {
busy = false;
}
}
}
document
.querySelector('button')
.addEventListener('click', triggerOnce(() => {
// 要做的事
}));