ajax三剑客,TypeScript版Ajax包括json、jsonp、post等请求

这个博客介绍了如何使用TypeScript编写一个Ajax库,支持json、jsonp和post请求,利用Promise和async/await解决回调问题。库包含对象遍历、类型检查、对象转query字符串等功能,并提供了jsonp的实现,支持超时和错误处理。示例展示了如何在实际项目中使用该库进行异步请求。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

TypeScript版Ajax包括json、jsonp、post等请求,使用Promise 对象返回结果,支持async/await解决回调地狱,书写更舒适。const hasOwnProperty = Object.prototype.hasOwnProperty;

interface EachObject {

[ key: string ]: any,

readonly length?: number,

}

function forEach(

obj: EachObject,

iterator: (value?: any, key?: number | string, obj?: EachObject) => boolean | void,

context?: Object

) {

if (!obj) {

return;

}

if (obj.length && obj.length === +obj.length) {

for (let i = 0; i < obj.length; i++) {

if (iterator.call(context, obj[i], i, obj) === true) return;

}

} else {

for (const k in obj) {

if (hasOwnProperty.call(obj, k)) {

if (iterator.call(context, obj[k], k, obj) === true) return;

}

}

}

}

const Types: {

[key: string]: (obj: Object) => boolean;

} = {};

const _toString: () => string = Object.prototype.toString;

forEach([

'Array',

'Boolean',

'Function',

'Object',

'String',

'Number',

], (name: number) => {

Types[`is${name}`] = function (obj: Object) {

return _toString.call(obj) === `[object ${name}]`;

}

});

// Object to queryString

function serialize(obj: EachObject): string {

const q: string[] = [];

forEach(obj, (val, key) => {

if (Types.isArray(val)) {

forEach(val, (v, i) => {

q.push(`${key}=${encodeURIComponent(v)}`);

});

} else {

q.push(`${key}=${encodeURIComponent(val)}`);

}

});

return q.join('&');

}

function parseJSON(str: string): Object {

try {

return JSON.parse(str);

} catch (e) {

try {

return (new Function(`return ${str}`))();

} catch (e) {}

}

return null;

}

const createXHR = 'XMLHttpRequest' in window ?

() => new XMLHttpRequest() :

() => new (window).ActiveXObject('Microsoft.XMLHTTP');

interface AjaxOptions {

url: string,

method?: string,

type?: ResType,

encode?: string,

timeout?: number,

credential?: boolean,

data?: EachObject,

}

export enum ResType {

TEXT = 'text',

JSON = 'json',

XML = 'xml',

}

function ajax(url: string): Promise;

function ajax(options: AjaxOptions): Promise;

function ajax(options): Promise{

return new Promise((

resolve: (data: any, status: number, xhr: XMLHttpRequest) => void,

reject: (error: Error) => void

) => {

if (Types.isString(options)) {

options = { url: options };

}

let {

url,

method = 'GET',

data,

type = ResType.JSON,

timeout = 1000 * 30,

credential,

encode = 'UTF-8',

} = options;

// 大小写都行,但大写是匹配HTTP协议习惯

method = method.toUpperCase();

// 对象转换成字符串键值对

let _data;

if (Types.isObject(data)) {

_data = serialize(data);

}

if (method === 'GET' && _data) {

url += (url.indexOf('?') === -1 ? '?' : '&') + _data

}

const xhr = createXHR();

if (!xhr) {

return null;

}

let isTimeout = false;

let timer;

if (timeout > 0) {

timer = setTimeout(() => {

// 先给isTimeout赋值,不能先调用abort

isTimeout = true;

xhr.abort();

}, timeout);

}

xhr.onreadystatechange = () => {

if (xhr.readyState === 4) {

if (isTimeout) {

reject(new Error('request timeout'));

} else {

onStateChange(xhr, type);

clearTimeout(timer);

}

}

};

xhr.open(method, url, true);

if (credential) {

xhr.withCredentials = true;

}

if (method === 'POST') {

xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded;charset=' + encode);

}

xhr.send(_data);

function onStateChange(

xhr: XMLHttpRequest,

type: ResType,

): void {

const { status } = xhr;

if (status >= 200 && status < 300) {

let result;

switch (type) {

case ResType.TEXT:

result = xhr.responseText;

break;

case ResType.JSON:

result = parseJSON(xhr.responseText);

break;

case ResType.XML:

result = xhr.responseXML;

break;

}

if (result !== undefined) {

resolve(result, status, xhr);

}

} else {

reject(new Error(xhr.status + ''));

}

xhr = null;

}

});

}

// exports to Shorthand

const api = {

method: ['get', 'post'],

type: ['text','json','xml']

};

// Shorthand Methods: IO.get, IO.post, IO.text, IO.json, IO.xml

const Shorthand = {};

forEach(api, (val, key) => {

forEach(val, item => {

Shorthand[item] = function (key, item) {

return function (opt) {

if (Types.isString(opt)) {

opt = { url: opt };

}

opt[key] = item;

return ajax(opt);

};

}(key, item);

});

});

function get(url: string): Promise;

function get(opt: AjaxOptions): Promise;

function get(opt): Promise {

return Shorthand['get'](opt);

}

function post(url: string): Promise;

function post(opt: AjaxOptions): Promise;

function post(opt): Promise {

return Shorthand['post'](opt);

}

function text(url: string): Promise;

function text(opt: AjaxOptions): Promise;

function text(opt): Promise {

return Shorthand['text'](opt);

}

function json(url: string): Promise;

function json(opt: AjaxOptions): Promise;

function json(opt): Promise {

return Shorthand['json'](opt);

}

function xml(url: string): Promise;

function xml(opt: AjaxOptions): Promise;

function xml(opt): Promise {

return Shorthand['xml'](opt);

}

export { ajax, get, post, text, json, xml };

function generateRandomName(): string {

let uuid = ''

const s = []

const hexDigits = '0123456789ABCDEF'

for (let i = 0; i < 32; i++) {

s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1)

}

// bits 12-15 of the time_hi_and_version field to 0010

s[12] = '4'

// bits 6-7 of the clock_seq_hi_and_reserved to 01

s[16] = hexDigits.substr((s[16] & 0x3) | 0x8, 1)

uuid = 'jsonp_' + s.join('')

return uuid

}

interface JSONPOptions {

url: string,

data?: EachObject,

timestamp?: boolean,

timeout?: number,

jsonName?: string,

jsonpCallback?: string,

charset?: string,

}

const ie678 = eval('!-[1,]');

const head = document.head || document.getElementsByTagName('head')[0];

function jsonpCore(options): Promise {

return new Promise((resolve, reject) => {

let {

url,

data = {},

timestamp = false,

timeout = 1000 * 30,

jsonName = 'callback',

jsonpCallback = generateRandomName(),

charset,

} = options;

let script = document.createElement('script');

let done = false;

function callback(isSucc = false) {

if (isSucc) {

done = true;

} else {

reject(new Error('network error.'));

}

// Handle memory leak in IE

script.onload = script.onerror = (script).onreadystatechange = null;

if (head && script.parentNode) {

head.removeChild(script);

script = null;

window[jsonpCallback] = undefined;

}

}

function fixOnerror() {

setTimeout(() => {

if (!done) {

callback();

}

}, timeout);

}

if (ie678) {

(script).onreadystatechange = function() {

const readyState = this.readyState;

if (!done && (readyState == 'loaded' || readyState == 'complete')) {

callback(true)

}

}

} else {

script.onload = function() {

callback(true)

}

script.onerror = function() {

callback()

}

if ((window).opera) {

fixOnerror()

}

}

if (charset) {

script.charset = charset;

}

const search = serialize({

...data,

[jsonName]: jsonpCallback,

});

url += (url.indexOf('?') === -1 ? '?' : '&') + search

if (timestamp) {

url += `&ts=${new Date().getTime()}`;

}

window[jsonpCallback] = function (json) {

resolve(json);

}

script.src = url;

head.insertBefore(script, head.firstChild);

});

}

// 调用此jsonp方法,只传入url即可

function jsonp(url: string): Promise;

// 调用此jsonp方法,传入的参数为对象,对象内的属性有url,data,调用成功后返回then(data->接口中返回的值)函数

function jsonp(opt: JSONPOptions): Promise;

function jsonp(opt): Promise {

if (Types.isString(opt)) {

opt = { url: opt };

}

return jsonpCore(opt);

}

export { jsonp };

例如:新建IO.js,把代码复制粘贴进去,在需要的地方import即可:import { jsonp } from "./IO";

....

private async ajaxCheckUser(){

const {code} = await jsonp(`${AjaxUrl}auth/checkname`);

if(code != 200) return;

//......

}

.....

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值