promise源码分析


// 判断变量否为function
const isFunction = variable => typeof variable === 'function'
// 定义Promise的三种状态常量
const PENDING = 'PENDING'
const FULFILLED = 'FULFILLED'
const REJECTED = 'REJECTED'

class MyPromise {
	constructor(handle) {
		if (!isFunction(handle)) {
			throw new Error('MyPromise must accept a function as a parameter')
		}
		// 添加状态
		this._status = PENDING
		// 添加状态
		this._value = undefined
		// 添加成功回调函数队列
		this._fulfilledQueues = []
		// 添加失败回调函数队列
		this._rejectedQueues = []
		// 执行handle
		try {
			handle(this._resolve.bind(this), this._reject.bind(this))
		} catch (err) {
			this._reject(err)
		}
	}
	// 添加resovle时执行的函数
	_resolve(val) {
		const run = () => {
			if (this._status !== PENDING) return
			this._status = FULFILLED
			// 依次执行成功队列中的函数,并清空队列
			const runFulfilled = (value) => {
				let cb;
				while (cb = this._fulfilledQueues.shift()) {
					cb(value)
				}
			}
			// 依次执行失败队列中的函数,并清空队列
			const runRejected = (error) => {
				let cb;
				while (cb = this._rejectedQueues.shift()) {
					cb(error)
				}
			}
			/* 如果resolve的参数为Promise对象,则必须等待该Promise对象状态改变后,
			  当前Promsie的状态才会改变,且状态取决于参数Promsie对象的状态
			*/
			if (val instanceof MyPromise) {
				val.then(value => {
					this._value = value
					runFulfilled(value)
				}, err => {
					this._value = err
					runRejected(err)
				})
			} else {
				this._value = val
				runFulfilled(val)
			}
		}
		// 为了支持同步的Promise,这里采用异步调用
		setTimeout(run, 0)
	}
	// 添加reject时执行的函数
	_reject(err) {
		if (this._status !== PENDING) return
		// 依次执行失败队列中的函数,并清空队列
		const run = () => {
			this._status = REJECTED
			this._value = err
			let cb;
			while (cb = this._rejectedQueues.shift()) {
				cb(err)
			}
		}
		// 为了支持同步的Promise,这里采用异步调用
		setTimeout(run, 0)
	}
	// 添加then方法
	then(onFulfilled, onRejected) {
		const { _value, _status } = this
		// 返回一个新的Promise对象
		return new MyPromise((onFulfilledNext, onRejectedNext) => {
			// 封装一个成功时执行的函数
			let fulfilled = value => {
				try {
					if (!isFunction(onFulfilled)) {
						onFulfilledNext(value)
					} else {
						let res = onFulfilled(value);
						if (res instanceof MyPromise) {
							// 如果当前回调函数返回MyPromise对象,必须等待其状态改变后在执行下一个回调
							res.then(onFulfilledNext, onRejectedNext)
						} else {
							//否则会将返回结果直接作为参数,传入下一个then的回调函数,并立即执行下一个then的回调函数
							onFulfilledNext(res)
						}
					}
				} catch (err) {
					// 如果函数执行出错,新的Promise对象的状态为失败
					onRejectedNext(err)
				}
			}
			// 封装一个失败时执行的函数
			let rejected = error => {
				try {
					if (!isFunction(onRejected)) {
						onRejectedNext(error)
					} else {
						let res = onRejected(error);
						if (res instanceof MyPromise) {
							// 如果当前回调函数返回MyPromise对象,必须等待其状态改变后在执行下一个回调
							res.then(onFulfilledNext, onRejectedNext)
						} else {
							//否则会将返回结果直接作为参数,传入下一个then的回调函数,并立即执行下一个then的回调函数
							onFulfilledNext(res)
						}
					}
				} catch (err) {
					// 如果函数执行出错,新的Promise对象的状态为失败
					onRejectedNext(err)
				}
			}
			switch (_status) {
				// 当状态为pending时,将then方法回调函数加入执行队列等待执行
				case PENDING:
					this._fulfilledQueues.push(fulfilled)
					this._rejectedQueues.push(rejected)
					break
				// 当状态已经改变时,立即执行对应的回调函数
				case FULFILLED:
					fulfilled(_value)
					break
				case REJECTED:
					rejected(_value)
					break
			}
		})
	}
	// 添加catch方法
	catch(onRejected) {
		return this.then(undefined, onRejected)
	}
	finally(cb) {
		return this.then(
			value => MyPromise.resolve(cb()).then(() => value),
			reason => MyPromise.resolve(cb()).then(() => { throw reason })
		);
	}
	// 添加静态resolve方法
	static resolve(value) {
		// 如果参数是MyPromise实例,直接返回这个实例
		if (value instanceof MyPromise) return value
		return new MyPromise(resolve => resolve(value))
	}
	// 添加静态reject方法
	static reject(value) {
		return new MyPromise((resolve, reject) => reject(value))
	}
	// 添加静态all方法
	static all(list) {
		return new MyPromise((resolve, reject) => {
			/**
			 * 返回值的集合
			 */
			let values = []
			let count = 0
			for (let [i, p] of list.entries()) {
				// 数组参数如果不是MyPromise实例,先调用MyPromise.resolve
				this.resolve(p).then(res => {
					values[i] = res
					count++
					// 所有状态都变成fulfilled时返回的MyPromise状态就变成fulfilled
					if (count === list.length) resolve(values)
				}, err => {
					// 有一个被rejected时返回的MyPromise状态就变成rejected
					reject(err)
				})
			}
		})
	}
	// 添加静态race方法
	static race(list) {
		return new MyPromise((resolve, reject) => {
			for (let p of list) {
				// 只要有一个实例率先改变状态,新的MyPromise的状态就跟着改变
				this.resolve(p).then(res => {
					resolve(res)
				}, err => {
					reject(err)
				})
			}
		})
	}
	static any(list) {
		return new MyPromise((resolve, reject) => {
			let rejectNum = 0;
			for (let p of list) {
				this.resolve(p).then(value => {
					resolve(value);
				}, err => {
					++rejectNum;
					if (rejectNum == list.length) {
						reject(err);
					}
				}).catch()
			}
		});
	}
}

Promise.race = function (list) {
	return new Promise((resolve, reject) => {
		let len = list.length;
		for (let i = 0; i < len; i++) {
			this.resolve(list[i]).then(val => resolve(val), err => reject(err));
		}
	});
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
在上一篇笔记中,我们分析了 `upload` 组件内部的 `request` 方法,接下来我们继续分析 `upload` 组件的另一个核心方法——`handleChange`。 ## handleChange `handleChange` 方法是 `upload` 组件内部监听 `change` 事件的回调函数。当用户选择文件后,该方法会被调用。 ```javascript handleChange(ev) { const { target } = ev; const { fileList } = this; // 根据上传文件的状态,更新 fileList 中对应文件的状态 const files = toArray(target.files); this.uploadFiles(files); target.value = ''; }, ``` 首先,我们通过事件对象获取到当前用户选择的文件列表。接下来,调用了 `uploadFiles` 方法,将选择的文件列表作为参数传入,用于处理文件上传操作。 最后,我们将 input 元素的值重置为空,以便用户下一次可以选择同一个文件进行上传。 ## uploadFiles `uploadFiles` 方法是 `handleChange` 方法的内部方法,用于处理上传文件的具体操作。 ```javascript uploadFiles(files) { const postFiles = Array.prototype.slice.call(files); const remainCount = this.limit - this.fileList.length; const canPostFiles = postFiles.slice(0, remainCount); canPostFiles.forEach(file => { this.upload(file); }); }, ``` 首先,将选择的文件列表转换成数组 `postFiles`。接着,我们计算出还可以上传的文件数量,并从 `postFiles` 数组中截取出可上传文件的子数组 `canPostFiles`。 最后,我们遍历 `canPostFiles` 数组,分别调用 `upload` 方法上传每个文件。 ## upload `upload` 方法是 `uploadFiles` 方法的内部方法,用于处理单个文件的上传操作。 ```javascript upload(rawFile, file) { const { onPreview } = this.$listeners; if (!this.beforeUpload) { return this.post(rawFile); } const before = this.beforeUpload(rawFile); if (before && before.then) { before.then(processedFile => { if (Object.prototype.toString.call(processedFile) === '[object File]') { this.post(processedFile); } else { this.post(rawFile); } }, () => { this.abort(rawFile, file); }); } else if (before !== false) { this.post(before); } else { this.abort(rawFile, file); } if (onPreview) onPreview(file || rawFile); }, ``` 首先,我们判断是否存在 `beforeUpload` 属性。如果不存在,直接调用 `post` 方法上传文件。 如果存在 `beforeUpload` 属性,调用 `beforeUpload` 方法并传入当前待上传的文件 `rawFile` 作为参数。如果 `beforeUpload` 返回一个 Promise 对象,我们需要等待 Promise 的 resolve 后再进行具体的上传操作。 如果 `beforeUpload` 返回一个 `File` 对象,说明已经对待上传的文件进行了加工处理,我们需要使用修改后的文件进行上传操作。否则,我们使用原始的 `rawFile` 进行上传。 如果 `beforeUpload` 返回 false,说明不允许上传当前的文件,我们需要调用 `abort` 方法中止上传操作。 最后,我们触发 `onPreview` 事件,用于预览文件。 到这里,我们已经分析了 `upload` 组件内部的两个核心方法 `handleChange` 和 `uploadFiles`,以及 `upload` 方法的具体实现。在下一篇笔记中,我们将继续分析 `upload` 组件的其他方法。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值