今天在看文章都时候发现了手写promise的要求,扪心自问,我靠,我竟然一点思路都没有。这可不行,必须本身手撸一发,面的对不起本身的左右手。哎,又要学习,好累,不过还好,想一想都2020了,还不会本身手写promise,着实有点垃圾,仍是赶快搞起来吧。javascript
Promise是一种异步操做的解决方案,将写法复杂的传统的回调函数和监听事件的异步操做,用同步代码的形式表达出来。避免了多级异步操做的回调函数嵌套。简单的来讲就是为了解决回调地狱的问题。试想一下,下面这个代码你看这头疼不?若是在加几层呢就会出现金字塔的代码了,这样给咱们阅读代码和维护代码形成的很大的困扰。java
function a() {
function b() {
function c() {
function d() {}
d();
}
c();
}
b();
}
a();
复制代码
咱们将上面的代码用promise改写。这样是否是好多了。promise
a().then(b).then(c).then(d)
复制代码
咱们按照promiseA+的规范来写。不知道的同窗能够看看哦。异步
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))
}
}
复制代码
一个 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)
})
}
复制代码
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
- 若是 x 是 pending 状态,那么保留它(递归执行这个 promise 处理程序),直到 pending 状态转为 fulfilled 或 rejected 状态。
- 若是或当 x 状态是 fulfilled,resolve 它,而且传入和 promise1 同样的值 value。
- 若是或当 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(onReject) {
this.then(null, onReject)
}
复制代码
3.1 这里的 “平台代码”是指引擎,环境,和 promise 实现代码。实际上,这个要求确保 onFulfilled 和 onRejected 都在下一轮的事件循环中(一个新的栈)被异步调用。能够用宏任务,例如:setTimeout,setImmediate 或者微任务,例如:MutationObsever 或 process.nextTick 实现。 因为 promise 的实现被当作平台代码,因此它自己可能包含一个任务队列或 “trampoline” 的处理程序this
// 因此咱们要在全部resolve和reject的调用上加一个setTimeout()
// 咱们在resolve函数外面包裹一个
// 同理咱们也要在reject函数包裹一下
function resolve() {
setTimeout(()=>{
// 上面的内容同样
})
}
复制代码
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
}
复制代码