promise返回对象的then方法
我们手写promise中then方法的实现。第一步应该检测then方法传过来的参数是不是一个函数,如果是函数,我们就把他添加到chain里面, 成功和失败的里面去添加一个回调。
代码如下:
let chain = {
then:function(){
let args = arguments
tuples.forEach((tuple,i)=>{
let fn = toString.call(args[i] === '[object Function]') && args[i]
chain[tuple[1]](function(){
fn&&fn.apply(this,arguments)
})
})
}
}
这里的fn其实就是then方法里面的参数函数,所以我们要把参数传递给fn去执行。
相当于说我们有两个容器,一个是成功的,一个是失败的。注意,我们的fn不是说添加到成功的回调,而是在成功的回调里去调用。失败的函数也是这个意思。
then方法返回值仍然应该是一个promise
这一步其实很简单,就是思维要适应。我们在then方法里再调用一次Promise方法就可以了。
但是代码也要做相应的改造处理,即如果返回的是一个promise,我们应该怎么做。
那应该怎么判断呢? 我们可以通过检测是否是一个对象,而且这个对象里面有没有then方法。
let chain = {
then:function(){
let args = arguments
return Promise(function(resolve,reject){
tuples.forEach((tuple,i)=>{
let fn = toString.call(args[i] === '[object Function]') && args[i]
chain[tuple[1]](function(){
let returned = fn&&fn.apply(this,arguments)
if(returned && toString.call(returned.then === '[object Function]')){
returned.done(resolve)
returned.fail(reject)
}
})
})
})
}
总结: 其实我们实现promise分了两步走,第一步先是实现了一个工具函数container, 第二步是自定义的Promise,借助container的一些方法去实现了js中的Promise。
let cache = {} // 缓存对象
let container = function(flags){
flags = typeof flags === 'string' ? (cache[flags] || createFlags(flags)):extend({},flags)
let carryOut = false
let stack = []
let memory = false
let stackLen,stackPoint = 0
let fire = function(data){
let len = stack.length;
let i = stackPoint || 0
stackPoint = 0
memory = flags.memory && data // flags.memory存在就把data 赋值给变量memory
carryOut = true
for(;i<len;i++){
if(stack[i].apply(data[0],data[1]) === false && flags.stopOnFalse){
break
}
}
}
let obj = {
add:function(){
(function(args){
stackLen = stack.length
Array.from(args).forEach(item=>{
if(toString.call(item) === '[object Function]'){
if(!obj.has(item)){
stack.push(item)
}
}else{
throw new Error('请正确传参数')
}
})
})(arguments)
if(memory){
stackPoint = stackLen
fire(memory)
}
},
startBind(context,args){
args = args || []
args = [context,args]
if(!flags.once || !carryOut){
fire(args)
}
},
startup(){
obj.startBind(this,arguments)
},
has(fn){
return stack.indexOf(fn) > -1
}
}
return obj
}
// (flags.match(/\S+/g) 是根据空格去分割字符串为数组
function createFlags(flags){
let res = {}
let arr = flags.match(/\S+/g) || []
arr.forEach(item =>{
res[item] = true
})
return res
}
function extend(to,from){
for(let key in from){
to[key] = from[key]
}
return to
}
// 2
function Promise(func){
let tuples = [
["resolve",'done',container('once memory'),'resolved'],
["reject",'fail',container('once memory'),'rejected'],
]
let state = 'pending'
let protect = {}
let chain = {
then:function(){
let args = arguments
return Promise(function(resolve,reject){
tuples.forEach((tuple,i)=>{
let fn = toString.call(args[i] === '[object Function]') && args[i]
chain[tuple[1]](function(){
let returned = fn&&fn.apply(this,arguments)
if(returned && toString.call(returned.then === '[object Function]')){
returned.done(resolve)
returned.fail(reject)
}
})
})
})
}
} //promise返回的是一个对象
tuples.forEach((tuple,i)=>{
let list = tuple[2]
let stateString = tuple[3]
if(stateString){
list.add(function(){
state = stateString
})
}
chain[tuple[1]] = list.add
protect[tuple[0]] = function(){
protect[tuple[0]+'Bind'](this,arguments)
}
protect[tuple[0]+'Bind'] = list.startBind
})
if(func){
func.call(chain,protect['resolve'],protect['reject'])
}
return chain
}