都2020了,也该会本身手写一个promise了

写在前面

今天在看文章都时候发现了手写promise的要求,扪心自问,我靠,我竟然一点思路都没有。这可不行,必须本身手撸一发,面的对不起本身的左右手。哎,又要学习,好累,不过还好,想一想都2020了,还不会本身手写promise,着实有点垃圾,仍是赶快搞起来吧。javascript


promise的几点要求

  1. 什么是promise?
  2. promise解决的什么问题?
  3. 咱们本身实现一个promise。

什么是promise?

Promise是一种异步操做的解决方案,将写法复杂的传统的回调函数和监听事件的异步操做,用同步代码的形式表达出来。避免了多级异步操做的回调函数嵌套。简单的来讲就是为了解决回调地狱的问题。试想一下,下面这个代码你看这头疼不?若是在加几层呢就会出现金字塔的代码了,这样给咱们阅读代码和维护代码形成的很大的困扰。java

function a() {
  function b() {
    function c() {
      function d() {}
      d();
    }
    c();
  }
  b();
}
a();
复制代码

promise解决了什么问题?

咱们将上面的代码用promise改写。这样是否是好多了。promise

a().then(b).then(c).then(d)
复制代码

实现一个Promise

咱们按照promiseA+的规范来写。不知道的同窗能够看看哦。异步

Promise类

const PENDING = pending
const FULFILLED = fulfilled
const REJECTED = rejected
class Promise {
	constructor(exextuor) {
		this.exextuor = exextuor
		this.states = PENDING
		this.onResolveCallbacks = []
		this.onRejectCallbacks = []
	}
	function resolve() {}
	function reject() {}
	
	if(exextuor) {
		try {
			exextuor(resolve, reject)
		}catch(e) {
			reject(e)
		}
	}
}

复制代码

上面的代码很简单,咱们一个resolve的调度栈,一个reject的调度栈,声明resolve和reject函数,并执行exextuor若是报错,将reject执行。 ####resolve和reject函数(2.1规范) 一个 promise 有且只有一个状态(pending,fulfilled,rejected 其中之一) pending 状态时可能会转变为 fulfilled 或 rejected 状态。fulfilled 状态时:不能再状态为任何其余状态,必须有一个 value,且不可改变。 rejected 状态时:不能再状态为任何其余状态,必须有一个 reason,且不可改变。函数

function resolve(value) {
	if(value instanceof Promise) {
		try{
			value.then(resolve, reject)
		}catch(e) {
			reject(e)
		}
	}
	if(this.states = PENDING) {
		this.states = FULFILLED
		this.value = value
		this.onResolveCallbacks.forEach(cb => cb(this.value))
	}
}
function reject(reason) {
	if(this.states = PENDING) {
		this.states = REJECTED
		this.reason = reason
		this.onRejectCallbacks.forEach(cb => cb(this.reason))
	}
}
复制代码

then函数(2.2规范)

一个 promise 必须提供一个 then 方法,用来获取当前或最终的 value 或 reason,一个 promise 的 then 方法接受两个参数:promise.then(onFulfilled, onRejected)学习

then(onFulfilled, onRejected) {
	onFulfilled = typeof onFulfilled === "function" ? onFulfilled : value => value
	onRejected = typeof onRejected === "function" ? onRejected : reason => throw reason
	if(this.states = FULFILLED) {
		this.x = onFulfilled(this.value)
	}
	if(this.states = REJECTED) {
		this.x = onRejected(this.reason)
	}
	if(this.states = PENDING) {
		this.onResolveCallbacks.push(() => {
			this.x = onFulfilled(this.value)
		})
		this.onRejectCallbacks.push(() => {
			this.x = onRejected(this.reason)
		})
	}
复制代码

then函数的链式调用

promise 的 then 能够链式调用屡次,若是或当 promise 转态是 fulfilled 时,全部的 onFulfilled 回调回以他们注册时的顺序依次执行。若是或当 promise 转态是 rejected 时,全部的 onRejected 回调回以他们注册时的顺序依次执行。测试

let primise2
if(this.states = FULFILLED) {
	return primise2 = new Promise((resole, reject) => {
		// 若是在执行onFulfilled的时候有异常咱们要将primise2的reject执行
		try {
			let x = onFulfilled(this.value)
			// 对返回值进行处理,由于这个值多是个promise
			resolvePromise(primise2, x, resole, reject)
		} catch(e) {
			reject(e)
		}
	})
}
复制代码

注意上面的三个判断的处理基本同样,咱们都要对结果处理。resolvePromise一下。 ####resolvePromise(2.3规范) 2.3.1 若是返回的 promise1 和 x 是指向同一个引用(循环引用),则抛出错误 2.3.2 若是 x 是一个 promise 实例,则采用它的状态ui

  1. 若是 x 是 pending 状态,那么保留它(递归执行这个 promise 处理程序),直到 pending 状态转为 fulfilled 或 rejected 状态。
  2. 若是或当 x 状态是 fulfilled,resolve 它,而且传入和 promise1 同样的值 value。
  3. 若是或当 x 状态是 rejected,reject 它,而且传入和 promise1 同样的值 reason
const PENDING = pending
const FULFILLED = fulfilled
const REJECTED = rejected

function resolvePromise(promise2, x, resolve, reject) {
	if(promise2 === x) {
		return reject(new TypeError('循环引入!'))
	}
	
	// 用于resolve, reject只调用一次
	let called = false
	
	// x是一个promise
	if(x instanceof Promise) {
		if(x.status === PENDING) {
			x.then((y)=>{
				// 有可能y仍是一个promise
				resolvePromise(promise2, y, resolve, reject)
			}, reject)
		} else {
			x.then(resolve, reject)
		}
	} else if(x !== null && (typeof x === 'function' || typeof x === 'object')) {
	// x是一个thenable的对象
		try{
			// 有可能在区x.then的时候异常
			let then = x.then
			if(typeof x === 'function') {
				// 这是咱们本身的promise和别人的promise的交互
				then.call(x, (z)=>{
					// 有可能z仍是一个promise
					if(called) return
					called = true
					resolvePromise(promise2, z,resolve, reject)
				}, (err)=>{
					if(called) return
					called = true
					reject(err)
				})
			}else {
				// 说明x是一个普通对象
				resolve(x)
			}
		}catch(e) {
			reject(e)
		}
	} else {
		// x是个普通值
		if(called) return
		called = true
		resolve(x)
	}
}
复制代码

catch函数

catch(onReject) {
	this.then(null, onReject)
}
复制代码

异步调用(3.1规范)

3.1 这里的 “平台代码”是指引擎,环境,和 promise 实现代码。实际上,这个要求确保 onFulfilled 和 onRejected 都在下一轮的事件循环中(一个新的栈)被异步调用。能够用宏任务,例如:setTimeout,setImmediate 或者微任务,例如:MutationObsever 或 process.nextTick 实现。 因为 promise 的实现被当作平台代码,因此它自己可能包含一个任务队列或 “trampoline” 的处理程序this

// 因此咱们要在全部resolve和reject的调用上加一个setTimeout()
// 咱们在resolve函数外面包裹一个
// 同理咱们也要在reject函数包裹一下
function resolve() {
	setTimeout(()=>{
		// 上面的内容同样
	})
}
复制代码

promise.all

Promise.all = function(promises) {
	return new Promise((resolve, reject)=>{
		let res = []
		let count = 0
		function done(i, result) {
			res[i] = result
			if(++count === promises.length) {
				resolve(res)
			}
		}
		for(let i = 0; i<promises.length; i++) {
			done.call(null, i,res)
		}
	}, reject)
}
复制代码

测试结果

Promise.deferred = Promise.deferred = function() {
	let defer = {}
	defer.promise = new Promise((resolve, reject) => {
		defer.resolve = resolve
		defer.reject = reject
	})
	return defer
}
复制代码

咱们测试用用例测试。基本全部的用例所有经过。好了这样一个promise基本实现。
相关文章
相关标签/搜索