实现一个Promise
参考:
在开发过程中,已经使用的非常多了;多以解决ajax
获取数据回调的问题;
基本使用:
getData().then(res=>{
console.log(res);
})
function getData(){
return new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve({
name:"admin",
age:"23"
});
});
})
}
Promise
不是新技术,它只是一个规范,任何人都可以按照此规范去实现自己的处理逻辑;并应用于自己的代码中。
基本特性
Promise
是一个对象或者函数,它拥有的方法必须符合Promise
规范。- 拥有一个
then
方法,具有thenable
特性(伪Promise
对象); - 返回值
resolve
是合法的javascript
值,包括undefined
/Promise
实例/thenable
对象; - 有被拒绝
rejected
的原因;
状态
在某一时刻必须是三个状态之一:pending
等待期/fulfilled
完成/rejected
被拒绝(不等于失败)
状态转换:
- 由
pending
转换为其他两个状态之一:
- 转换为
fulfilled
状态后,状态不会在发生变化;必须有返回值; - 转换为
rejected
状态后,状态不会在发生变化;必须有原因;
then
方法
必须存在then
方法,用来访问状态变化之后的返回值(被拒原因);
promise.then(onFulfilled,onRejected)
-
可选参数;
onFulfilled
,onRejected
必须是一个函数;不是则被忽略; :: -
状态变化为
fulfilled
时,调用onFulfilled
函数一次 ,将返回值作为第一个参数; -
状态变化为
rejected
时,调用onRejected
函数一次,将被拒原因作为第一个参数; -
onFulfilled
/onRejected
仅作为函数调用,内部无this
对象; -
有多个
Promise
实例被执行时,按照他们原有的顺序访问结果(调用多次then
);比如Promise.all()
-
调用
promise.then(onFulfilled,onRejected)
必须返回一个Promise
实例:- 调用
then()
方法返回一个有效值,则这个值作为新Promise
实例状态为fulfilled
的返回值; - 调用
then()
方法代码执行错误,或手动throw
一个Exception
,则这个e
作为新Promise
实例状态为rejected
的原因; onFulfilled
不是有效函数,则将原Promise
实例状态转换后的返回值作为返回值;onRejected
不是有效函数,则将原Promise
实例状态转换后的被拒原因作为实例被拒原因;
- 调用
Promise
返回结果处理流程
针对返回值x
做一下假设,并按照此流程处理:
x
有可能是一个对象或者函数,自身实现了then
方法,属于不合规的实现,也需按照流程处理。
promise
表示当前实例,x
表示返回值resolve
; 官方表示[[Resolve]](promise,x)
说明:
- 使用
then
方法操作是一种异步调用,也就是如果由于一些因素导致状态还处于pending
,我们调用then
就不会立即拿到结果;那它内部就必须等待到结果才能返回,使用setTimeout
延时处理,如果获得了结果,就执行。 this
对象不可用,在严格模式是undefined
,混杂模式下为全局对象;- 在实现中注意如何处理这种情况
promise2 === promise1
; - 判断返回值
x
是是否是当前Promise
的一个实例,才能按照当前状态处理它; - 避免对返回值
x
多次调用x.then()
,确保一致性; - 正视多次调用
then()
,实现代码中不应限制调用次数;只有真的无限循环时才会允许抛出TypeError
错误;
实现过程
本来想自己慢慢写的,却熬不住耐心去尝试;突然就看到了一个地址的实现promise实现 ; 另加一点自己的想法;
-
Promise
是一个函数或对象(用函数来写);三个状态、初始状态、状态转换后的值、状态改变之后的回调、状态改变之后的处理函数;当前返回的值不是一个函数或对象时,基本就可以这样处理;如果是函数或对象还要额外处理。
function Promise(){ // 三个状态 const states = { PEDNING:"pending", FULFILLED:"fulfilled", REJECTED:"rejected" }; // 初始当前状态 let state = states.PEDNING; // 存储状态 改变之后的值 let value = null; // 存储fulfilled 或 rejected 需要回调的函数 // 同一个Promise对象会多次调用 `.then()` , let handles = []; // 成功之后的函数 function fulfilled(result){ state = states.FULFILLED; value = result; } // 失败之后 、被拒之后 的函数 function rejected(err){ state = states.REJECTED; value = err; } }
-
当获取的值不是简单值,是一个函数或独享;需要处理是否存在
then
方法,如果存在,则调用;不存在则进行简单状态转换。
resolve()
用来针对性处理返回的结果值如果是一个对象或函数且具有then()
方法时递归调用;
保证状态值只改变一次,且调用fulfilled()
或rejected()
一次;第一阶段说明文字很长,有流程处理图,还请耐心看完,理解就会很快。
function Promise(){ // ... // 处理更深层次的值,返回值是函数、对象 function resolve(result){ try{ // 返回的结果是否存在 `then` 函数,是否可调用 ; 手动实现 getThen()方法。 let then = getThen(result); if(then){ // 存在 then 方法,则属于伪 Promise; 但还是要按照Promise的流程处理它; // 手动实现 doResolve()方法 doResolve(then.bind(result),resolve,rejected); return; } fulfilled(result); }catch(e){ rejected(e); } } } /** * 判断传入的值是否是函数或者对象, * 并且是否拥有then方法,并返回 * @param {需要判断 处理的值} value */ function getThen(value){ let t = typeof value; if(value&&(t === 'object' || t === 'function')){ let thenMethods = value.then; if(typeof thenMethods === 'function'){ return thenMethods; } } return null; } /** * 1. 需要处理的then 方法,不确定该 then方法是否是规范的Promise.then() ; * 2. try...catch..捕获可能调用方法出现的错误; * 3. 如果该 then 方法符合规范,则按照正常的 Promise 流程处理 * 4. 调用处理 onFulfilled方法也就是 resolve() 可以处理多次递归的问题; * @param {*} fn * @param {*} onFulfilled * @param {*} onRejected */ function doResolve(fn,onFulfilled,onRejected){ let done = false; try{ fn(value=>{ if(done) return; done = true; onFulfilled(value); },reason=>{ if(done) return; done = true; onRejected(reason); }); }catch(e){ if(done) return; done = true; onRejected(e); } }
-
按照正常的调用
Promise
,有一个参数(resolve,reject)
,用于手动处理返回的值。function Promise(fn){ // ... // 考虑到递归调用,保证状态只改变一次; // fulfilled() 调用一次;rejected()调用一次; doResolve(fn,resolve,rejected); }
-
接受用户调用
Promise
实例后.then
方法的处理函数;
说明
done
函数时then
方法的一个简化版,如果不考虑返回值是函数、对象;多次调用等问题就可以直接使用done()
方法;
有了done
方法,多次调用then()
方法以返回多个Promise
实例而分割处理,不会造成混乱;// 为了保证 处理函数 handle 时异步的; this.done = function(onFulfilled,onRejected){ setTimeout(()=>{ handle({ onFulfilled:onFulfilled, onRejected:onRejected }); }); } // 实现 then() 方法 // 按照then 的规范实现: // 1. 必须返回一个Promise实例 this.then = function(onFulfilled,onRejected){ let self = this; return new Promise(function(resolve,reject){ return self.done((result)=>{ if(typeof onFulfilled === 'function'){ try{ return resolve(onFulfilled(result)); }catch(err){ return reject(err); } }else{ return resolve(result); } },(error)=>{ if(typeof onRejected === 'function'){ try{ return resolve(onRejected(error)); }catch(e){ return reject(e); } }else{ return reject(error); } }) }); }
测试结果
- 实例测试结果展示
- 通过工具测试结果
promises-aplus-tests
错误一:如果onFulfilled/onRejected
就没必要在延时后调用了,而是在之前进行调用;
错误二:当返回值x
和当前实例promise
相同时,没有抛出错误TypeError