AbortController取消fetch请求实例页面

回到相关文章 »

展示

点击下面每一个按钮都会请求,请求时间在0.5s-1.5s之间随机,快速点击,看看返回的数据是哪一个?

代码

CSS代码:
.container {
    max-width: 600px;
    margin-inline: auto;
}
.operate {
    display: flex;
    gap: .5rem;
}
.operate button {
    flex: 1;
    font-size: 100%;
    height: 2.5rem;
}
.result {
    display: grid;
    border: 1px solid #ddd;
    background-color: #f5f5f5;
    margin-block: 1rem;
    padding: 1.5rem;
    place-items: center;
}
.result:empty::before {
    content: '结果返回区域';
    color: darkgray;
}
.result.loading {
    font-size: 0;
}
.result.loading::before {
    content: '';
    border: 2px solid deepskyblue;
    border-top-color: transparent;
    border-radius: 50%;
    animation: spin 1s linear infinite;
    width: 1.5rem; height: 1.5rem;
    box-sizing: border-box;
}
@keyframes spin {
    from { transform: rotate(0); }
    to { transform: rotate(360deg); }
}
.error {
    color: red;
}
HTML代码:
<div class="container">
    <p>点击下面每一个按钮都会请求,请求时间在0.5s-1.5s之间随机,快速点击,看看返回的数据是哪一个?</p>
    <div id="operate" class="operate">
        <button value="zhang">返回“zhang”</button>
        <button value="xin">返回“xin”</button>
        <button value="xu">返回“xu”</button>
    </div>
    <div id="result" class="result"></div>
</div>
JS代码:
const data = {};

// 对象和视图关联
Object.defineProperty(data, 'loading', {
    get: function () {
        return result.classList.contains('loading');
    },
    set: function (val) {
        result.classList[val ? 'add' : 'remove']('loading');
    }
})

// 构造器对象
let conrtoller = null;

// 按钮点击
operate.addEventListener('click', function (event) {
    if (event.target.matches('button')) {
        // 构造 AbortController 对象
        if (data.conrtoller) {
            conrtoller = data.conrtoller;
        } else {
            conrtoller = new AbortController();
            data.conrtoller = conrtoller;
        }
        // 如果正在请求,终止
        if (data.loading) {
            conrtoller.abort();

            // 构建新的 AbortController
            conrtoller = new AbortController();
            data.conrtoller = conrtoller;
        }

        data.loading = true;

        // 请求逻辑
        fetch('./getVal.php?val=' + event.target.value, {
            signal: conrtoller.signal
        }).then(res => res.text()).then(text => {
            data.loading = false;
            delete data.conrtoller;
            // 显示内容
            result.innerHTML = text;
        }).catch(error => {
            // 显示出错提示
            if (!/cancel|abort/i.test(error)) {
                delete data.conrtoller;
                data.loading = false;
                result.innerHTML = '<span class="error">' + error + '</span>';
            }
        });
    }
});