230 lines
6.6 KiB
JavaScript
Raw Normal View History

/* eslint-disable */
import EventTarget from './EventTarget.js'
const _url = new WeakMap()
const _method = new WeakMap()
const _requestHeader = new WeakMap()
const _responseHeader = new WeakMap()
const _requestTask = new WeakMap()
let fs;
function _triggerEvent(type, event = {}) {
event.target = event.target || this
if (typeof this[`on${type}`] === 'function') {
this[`on${type}`].call(this, event)
}
}
function _changeReadyState(readyState, event = {}) {
this.readyState = readyState
event.readyState = readyState;
_triggerEvent.call(this, 'readystatechange', event)
}
function _isRelativePath(url) {
return !(/^(http|https|ftp|wxfile):\/\/.*/i.test(url));
}
export default class XMLHttpRequest extends EventTarget {
constructor() {
super();
/*
* TODO 这一批事件应该是在 XMLHttpRequestEventTarget.prototype 上面的
*/
this.onabort = null
this.onerror = null
this.onload = null
this.onloadstart = null
this.onprogress = null
this.ontimeout = null
this.onloadend = null
this.onreadystatechange = null
this.readyState = 0
this.response = null
this.responseText = null
this.responseType = ''
this.responseXML = null
this.status = 0
this.statusText = ''
this.upload = {}
this.withCredentials = false
_requestHeader.set(this, {
'content-type': 'application/x-www-form-urlencoded'
})
_responseHeader.set(this, {})
}
abort() {
const myRequestTask = _requestTask.get(this)
if (myRequestTask) {
myRequestTask.abort()
}
}
getAllResponseHeaders() {
const responseHeader = _responseHeader.get(this)
return Object.keys(responseHeader).map((header) => {
return `${header}: ${responseHeader[header]}`
}).join('\n')
}
getResponseHeader(header) {
return _responseHeader.get(this)[header]
}
open(method, url /* async, user, password 这几个参数在小程序内不支持*/ ) {
_method.set(this, method)
_url.set(this, url)
_changeReadyState.call(this, XMLHttpRequest.OPENED)
}
overrideMimeType() {}
send(data = '') {
if (this.readyState !== XMLHttpRequest.OPENED) {
throw new Error("Failed to execute 'send' on 'XMLHttpRequest': The object's state must be OPENED.")
} else {
const url = _url.get(this)
const header = _requestHeader.get(this)
const responseType = this.responseType
const relative = _isRelativePath(url)
let encoding;
if (responseType === 'arraybuffer') {
// encoding = 'binary'
} else {
encoding = 'utf8'
}
delete this.response;
this.response = null;
const onSuccess = ({ data, statusCode, header }) => {
statusCode = statusCode === undefined ? 200 : statusCode;
if (typeof data !== 'string' && !(data instanceof ArrayBuffer)) {
try {
data = JSON.stringify(data)
} catch (e) {
data = data
}
}
this.status = statusCode
if (header) {
_responseHeader.set(this, header)
}
_triggerEvent.call(this, 'loadstart')
_changeReadyState.call(this, XMLHttpRequest.HEADERS_RECEIVED)
_changeReadyState.call(this, XMLHttpRequest.LOADING)
this.response = data
if (data instanceof ArrayBuffer) {
Object.defineProperty(this, 'responseText', {
enumerable: true,
configurable: true,
get: function() {
throw "InvalidStateError : responseType is " + this.responseType;
}
});
} else {
Object.defineProperty(this, 'responseText', {
enumerable: true,
configurable: true,
value: data
});
}
_changeReadyState.call(this, XMLHttpRequest.DONE)
_triggerEvent.call(this, 'load')
_triggerEvent.call(this, 'loadend')
}
const onFail = ({ errMsg }) => {
// TODO 规范错误
if (errMsg.indexOf('abort') !== -1) {
_triggerEvent.call(this, 'abort')
} else {
_triggerEvent.call(this, 'error', {
message: errMsg
})
}
_triggerEvent.call(this, 'loadend')
if (relative) {
// 用户即使没监听error事件, 也给出相应的警告
console.warn(errMsg)
}
}
if (relative) {
var options = {
'filePath': url,
'success': onSuccess,
'fail': onFail
}
if (encoding) {
options['encoding'] = encoding;
}
if (!fs) {
fs = swan.getFileSystemManager();
}
fs.readFile(options)
return
}
swan.request({
data,
url: url,
method: _method.get(this),
header: header,
responseType: responseType,
success: onSuccess,
fail: onFail
})
}
}
setRequestHeader(header, value) {
const myHeader = _requestHeader.get(this)
myHeader[header] = value
_requestHeader.set(this, myHeader)
}
addEventListener(type, listener) {
if (typeof listener !== 'function') {
return;
}
this['on' + type] = (event = {}) => {
event.target = event.target || this
listener.call(this, event)
}
}
removeEventListener(type, listener) {
if (this['on' + type] === listener) {
this['on' + type] = null;
}
}
}
// TODO 没法模拟 HEADERS_RECEIVED 和 LOADING 两个状态
XMLHttpRequest.UNSEND = 0
XMLHttpRequest.OPENED = 1
XMLHttpRequest.HEADERS_RECEIVED = 2
XMLHttpRequest.LOADING = 3
XMLHttpRequest.DONE = 4