自己封装一个ajax

本文详细介绍了如何手动创建一个简单的AJAX实现,包括使用XMLHttpRequest对象进行GET请求,以及添加请求和响应拦截器来处理超时、错误和数据转换。同时,展示了如何通过事件绑定实现请求的取消功能,确保在特定条件下能够中断请求过程。
摘要由CSDN通过智能技术生成

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

  • 手动实现一个简单的ajax, 通过xhr对象,去写个简单的流程。 javascript function ajax(url,onSuccess,onFailed) { const xhr = window.XMLHTTPRequest ? new XMLHTTPRequest() : new ActiveXObject(); xhr.open("get",url,true); xhr.send(); xhr.onreadystatechange = function () { if(xhr.readyState === 4) { if(xhr.status === 200) { onSuccess && onSuccess(xhr.responseText); } else { onFailed && onFailed(); } } } }

  • 封装请求的拦截

添加一些请求的拦截,设置请求超时时间,处理请求成功时的响应,

请求的拦截一般干什么? 请求的拦截一般做一些公共校验,如果通过返回config,resolve后继续往下链

响应的拦截一般干什么? 拦截错误,公共的请求报错,处理返回数据等

```js // ajax.html const adaptor = function (config) { return new Promise((resolve, reject) => { const xhr = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject("Mirosoft.XMLHttp"); xhr.open(config?.method.toUpperCase(), config?.url, true); xhr.send();

xhr.timeout = config?.timeout;
    xhr.onreadystatechange = function () {
        if (xhr.readyState === 4) {
            if (xhr.status === 200) {
                resolve(xhr.responseText);
            } else {
                reject("request error");
            }
        }
    };
});

};

// 处理请求成功时的响应 const dispatchRequest = function (config) { return adaptor(config).then( function (res) { return res; }, function (reason) { return Promise.reject(reason); } ); };

const req = function (config) { const chain = [dispatchRequest, undefined];

if (config?.interceptor) {
    chain.unshift(
        config?.interceptor?.fullfilled,
        config?.interceptor?.rejected
    );
}
if (config?.adaptor) {
    chain.push(config?.adaptor?.fullfilled, config?.adaptor?.rejected);
}

let promise = Promise.resolve(config);

while (chain.length) {
    promise = promise.then(chain.shift(), chain.shift());
}

return promise;

};

req({ method: "get", url: "http://127.0.0.1:5500/data.json", interceptor: { fullfilled: function (e) { console.log("请求被拦截住了", e); return e; // 一定要把config返回 }, }, adaptor: { fullfilled: function (e) { console.log("响应被拦截住了", e); return e; }, }, });

// data.json { "code": 0, "data": "返回数据了", "message": "成功", "success": true }

```

结果: 在这里插入图片描述

一定要把config返回,因为整体是链式结构的。resovePromise会把return的值resolve掉,作为接下来.then的result,否则拦截过后的页面的请求将获取不到数据和错误原因。

  • 实现一种请求的取消 写一个on/emit去绑定事件,在处理请求的时候处理,从外部得到的config.cancel,在这里用on绑定了abort事件为,cancel传进来的函数,接收一个参数,作为cancel的参数,然后请求中emit执行abort,并将取消请求的方法,报错等等作为一个参数传入emit,而我们最终的目的就是能在外部,去调用这个参数,所以当emit的时候,把取消请求的方法传入绑定的事件中,又通过刚刚on那里穿到cancel,这个时候我们只要将cancel回调中的参数执行就可以取消请求。

我们还做了request的拦截和response的拦截,将请求的响应导入到一个数组chain,将request的拦截放到请求响应的前面,将response的拦截响应放到请求响应之后,这样[interceptorFullFilled,interceptorFullRejected,fullFilled,rejected,adAptorFullfilled,adAptorRejected] 然后我们从数组的前面往后两个一组执行,就可以让请求依次执行request的拦截,请求,response的拦截。

``` let cc = null;

const mitt = { cache: {}, on: function (name, func) { this.cache[name] = func; }, emit: function (name, data) { const fn = this.cache[name]; fn && fn(data); }, };

const adaptor = function (config) { return new Promise((resolve, reject) => { let xhr = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject("Mirosoft.XMLHttp");

xhr.open(config?.method.toUpperCase(), config?.url, true); xhr.send();

xhr.onabort = function () { xhr = null; reject("[abort] request is aborted"); };

if (config.cancel) { mitt.emit("abort", function () { xhr.abort(); xhr = null; reject("【abort】current request is abort."); }); }

xhr.timeout = config?.timeout; xhr.onreadystatechange = function () { if (xhr.readyState === 4) { if (xhr.status === 200) { setTimeout(function () { resolve(xhr && xhr.responseText); }, 5000); } else { reject("request error"); } } }; }); };

// 处理请求成功时的响应 const dispatchRequest = function (config) { return adaptor(config).then( function (res) { return res; }, function (reason) { return Promise.reject(reason); } ); };

const req = function (config) { const chain = [dispatchRequest, undefined];

if (config?.interceptor) { chain.unshift( config?.interceptor?.fullfilled, config?.interceptor?.rejected ); }

if (config?.adaptor) { chain.push(config?.adaptor?.fullfilled, config?.adaptor?.rejected); }

if (config.cancel) { mitt.on("abort", function (func) { config.cancel(func); }); }

let promise = Promise.resolve(config);

while (chain.length) { promise = promise.then(chain.shift(), chain.shift()); }

return promise; };

req({ method: "get", url: "http://127.0.0.1:5500/3browser/01/data.json", interceptor: { fullfilled: function (e) { console.log("请求被拦截住了", e); return e; // 一定要把config返回 }, }, adaptor: { fullfilled: function (e) { console.log("响应被拦截住了", e); return e; }, }, cancel: function (onCancel) { cc = onCancel; }, }); setTimeout(function () { cc && cc(); }, 2000);

```

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值