相信你们对promise都有本身的见解,或者说实践经历,也可能还有些许朋友正在学习前端,恰好碰见了promise,想要找寻一下答案,我写这篇文章呢,也不是多么的详解promise这个机制,更多的是想对刚接触的朋友起到一个引导的做用,另外也是本身对自我认识的一个总结。前端
其实说直白一点,promise是现阶段解决异步问题的 终极 方案,针对棘手的回调地狱咱们每每不只是头疼,并且也不利于函数式编程,毕竟回调的写法着实不如同步的写法那样符合直觉。编程
function foo(res) {
let self = this
if (this.nick.length !== 0) {
uni.request({//第一次异步请求
url: 'https://........',
data: {
userid: self.$store.state.userInfo.ID,
faceurl: self.$store.state.userInfo.FaceURL,
nick: self.nick
},
success:function(res){
uni.request({//第二次异步请求
url: 'https://........',
data: {
userId: self.$store.state.userInfo.ID
},
success:function(res){
if (res.data.IsSuccess) {
self.$store.commit('refresh', res.data.User)
}
}
})
setTimeout( function () {
uni.navigateBack({
delta: 1
})
}, 1200)
},
complete: function (res) {
self.$api.msg(res.data.Msg)
}
})
}
}
复制代码
这样一系列回调下来,若是再须要发送一个请求的话,或者作一个其余的异步操做,这样嵌套层次就会很深,每一步异步操做都须要加在上一步的回调后面,而且这种写法不太利于函数式编程,不管是对于维护仍是追加内容都不很友好,整个代码结构像是 > 这种形状,那么下面来看看,一个promise的操做api
function logIn(provider){
let self = this
if(provider==='weixin' || provider==='sinaweibo'){
uni.getProvider({//获取uniapp支持的第三方数据(第一次异步)
service:'oauth'
}).then(data=>{
var [err,res] = data
var providers=res.provider
var flagIndex=providers.indexOf(provider)
if(flagIndex>-1){
return providers[flagIndex]
}
}).then(res=>{
return uni.login({//登录接口(第二次异步)
provider:res,
scopes:'auth_base',
timeout:20000,
})
}).then(data=>{
var [err,res] = data
if(res.errMsg==="login:ok"){
self.authResult=res.authResult
return res.authResult
}
}).then(res=>{
return uni.getUserInfo({//获取用户的信息(第三次异步)
provider:provider,
timeout:20000,
withCredentials:true
})
}).then(data=>{
var [err,res] = data
if(res.errMsg==="getUserInfo:ok"){
return res
}
}).then(res=>{
if(provider==='weixin')
self.getIsBindData.openid=res.userInfo.unionId
self.getDataWX.nickname=res.userInfo.nickName
self.getDataWX.headimgurl=res.userInfo.avatarUrl
self.getDataWX.openid=res.userInfo.unionId
self.getDataWX.unionid=res.userInfo.openId
return self.$Request.get(self.isbindUrl,self.getIsBindData,false)//发送请求判断是否绑定手机号(第四次异步)
}else if(provider==='sinaweibo'){//若是绑定的是微博
}
}).then(res=>{
if(provider==='weixin'){//若是是微信
if(res.Data.isBind){//若是绑定了
this.$store.commit('login', res.Data.user)
uni.switchTab({//跳去首页
url: '/pages/index/index'
})
}else if(!res.Data.isBind){//若是没绑定
console.log(1)
uni.navigateTo({
url:`............`,
})
}
}else{
}
})
}
}
复制代码
用promise的写法有木有很眼熟,像不像jq啊,这种链式调用就算有多步的异步函数写出来的代码依然很清晰,整个代码就够就像是 | ,一步一步接着来,似魔鬼的步伐promise
咱们模拟这样一个场景微信
function foo(num){
setTimeout(()=>{
return num+100
},1000)
};
foo(0);
复制代码
请问各位看官,这个100能够在1秒后能被拿到嘛?答案是不能拿到,由于咱们在1秒后已是异步的事情了,但如今有这样的需求,咱们恰恰就是须要num+100
来作后面的操做。app
function bar (num){
console.log(num-10)
return num-10
}
复制代码
咱们须要在foo
以后获得的数据放入bar
中在进行操做,换成往常的作法即是:异步
function foo(num){
setTimeout(()=>{
let res = num+100
bar(res)
},1000)
};
foo(100);
复制代码
那么在1秒后,咱们确实能够打印出190,可是若是十次,二十次,等等等这样的异步操做呢?每一步都须要上一步结算获得的数值进行下一步计算,整个代码会显得很冗余。ide
function foo(num,fn){
setTimeout(()=>{
fn(num+100)
},1000)
};
复制代码
那么咱们在调用的时候就须要写成foo(100,bar)
若是嵌套bar
函数也是个异步,而且还须要嵌套其余函数,这样下来真的时候头疼,烦都烦死了。可是用咱们的promise
就能够轻松搞定!!!!函数式编程
首先把foo重写一下函数
function foo(num){
return new Promise((res,rej)=>{//res,rej写成啥都无所谓
setTimeout(()=>{
res(num+100)
},1000)
})
}
复制代码
bar代码不变,咱们调用的时候就能够这么来了
foo(100).then(res=>{
bar(res)
})
复制代码
一样的会在1秒后继续打印出来190,并且若是要将这个值继续传递也很方便。
function foo(num){
return new Promise((res,rej)=>{//res,rej写成啥都无所谓
setTimeout(()=>{
res(num+100)
},1000)
})
};
function bar (num){
console.log(num-10);
return num-10
};
foo(100).then(res=>{
return bar(res)
}).then(res=>{
return bar(res)
}).then(res=>{
return bar(res)
}).then(res=>{
console.log('能够继续传递下去哦'+res)
return res
})
复制代码
各位在控制台上打印一下这个数据,看看是否是这样的:
.then
因此咱们立刻就要进入到真正的环节中。
首先实例化一个promise对象
let promise_a = new Promise((resolve,reject)=>{console.log('...code')})
复制代码
new Promise()
中接受一个参数 该参数是一个函数 我习惯性的写成了箭头函数,不懂箭头函数的朋友能够再去学习一下。 这个函数中接收两个参数 分别是:resolve,reject
其中resolve,reject
只是两个形参,一个表明成功,一个表明失败,不在意这俩写成啥,写成这样foo,bar
也无所谓 eg :let promise_a = new Promise((foo,bar)=>{console.log('...code')}) 同样的
那么咱们姑且认为这个resolve
就像是function
中的return
同样,reject
就相似throw
同样。 在一个函数中,promise到底应该这么用呢。 看代码:
function foo_(num){
return new Promise((res,rej)=>{//首先new一个promise 这个promise实例是必需要返回(return)的,否则将没法将这个数据吐出去
setTimeout(()=>{
try{
const a = num+1
//a = 1
res(a)//将正确的数据返出去 能够用.then接
}catch(e){
rej(e)//将错误的数据返出去 能够用.then接
}
})
})
};
复制代码
以上代码 若是a=1
被注释,那么成功的数据将被res(a)
抛出去,若是不被注释,那么就报错,就会被rej(e)
所有抛出去。
抛出去的数据将会被.then
接住
.then
.then
是实例化的promise对象的一个方法。.then()
接受两个参数,成功的回调函数,失败的回调函数即:
foo_(100).then(
success=>{//成功的回调
console.log(`success,成功的回调:${success}`)
},
error=>{//失败的回调
console.log(`error,失败的回调:${error}`)
}
)
复制代码
以上面的foo_
为例 首先咱们把 a = 1 注释掉
//首先咱们把 a = 1 注释掉
foo_(100).then(
success=>{//成功的回调
console.log(`success,成功的回调:${success}`)
},
error=>{//失败的回调
console.log(`error,失败的回调:${error}`)
}
)
复制代码
打印结果以下:
在以上代码中,success 其实就是foo_中res(a) 中的a 就像我上文所说,相似return
同样,是能抛出去,而且能被接住。只是能在.then
中接到。
如今 咱们将 // a = 1
的注释去掉,一样调用上方的代码: 首先咱们把 a = 1 去掉注释!!
//首先咱们把 a = 1 去掉注释!!
foo_(100).then(
success=>{//成功的回调
console.log(`success,成功的回调:${success}`)
},
error=>{//失败的回调
console.log(`error,失败的回调:${error}`)
}
)
复制代码
打印结果以下:
throw
同样,是能抛出去,而且能被接住。只是能在
.then
中接到。
以上方代码为例
如今,咱们再添加一个函数
同步函数:
function baz(num){
return num+10
}
咱们想在
foo_(100).then(
success=>{//成功的回调
console.log(`success,成功的回调:${success}`)
},
error=>{//失败的回调
console.log(`error,失败的回调:${error}`)
}
)
以后再将 success 或者 error 进行操做而且在传递下去
那么使用return 就好
咱们先把 foo_ 中的 a = 1 注释掉
function foo_(num){
return new Promise((res,rej)=>{//首先new一个promise 这个promise实例是必需要返回(return)的,否则将没法将这个数据吐出去
setTimeout(()=>{
try{
const a = num+1
//a = 1
res(a)//将正确的数据返出去 能够用.then接
}catch(e){
rej(e)//将错误的数据返出去 能够用.then接
}
})
})
};
在控制台上打出这段代码
foo_(100).then(
success=>{//成功的回调
let result = success+10
console.log(`success,成功的回调:${result}`)
return result
},
error=>{//失败的回调
let err = error
console.log(`error,失败的回调:${err}`)
return error
}
).then(
success=>{
let res = baz(success)
console.log(`res=${res}`)
},
error=>{
console.log(`这是一个错误:${error}`)
}
)
复制代码
打印结果:
咱们把 foo_ 中的 a = 1 去掉注释
function foo_(num){
return new Promise((res,rej)=>{//首先new一个promise 这个promise实例是必需要返回(return)的,否则将没法将这个数据吐出去
setTimeout(()=>{
try{
const a = num+1
a = 1
res(a)//将正确的数据返出去 能够用.then接
}catch(e){
rej(e)//将错误的数据返出去 能够用.then接
}
})
})
};
在控制台上打出这段代码
foo_(100).then(
success=>{//成功的回调
let result = success+10
console.log(`success,成功的回调:${result}`)
return result
},
error=>{//失败的回调
let err = error
console.log(`error,失败的回调:${err}`)
return error
}
).then(
success=>{
let res = baz(success)
console.log(`res=${res}`)
},
error=>{
console.log(`这是一个错误:${error}`)
}
)
复制代码
打印结果:
console.log(`这是一个错误:${error}`)
这一句 反而进入了
console.log(`res=${res}`)
中去呢。
好的,问题出来了,咱们继续讲.then
其实在每一次.then
的时候 不管是进入成功的回调,即:
success=>{
let res = baz(success)
console.log(`res=${res}`)
},
复制代码
仍是失败的回调,即:
error=>{
console.log(`这是一个错误:${error}`)
}
复制代码
都是能够认为是一个独立的 promise , 其后方的 .then 关注的是上一个的处理结果,
因此在处理这个问题的时候, .then以后的两个蓝色箭头所指的函数仅仅只处理黄色成功箭头函数以后的东西,由于根本就没有走到与黄色箭头的并列的error函数中去
error=>{
console.log(`这是一个错误:${error}`)
}
复制代码
就必须不管在
success=>{//成功的回调
let result = success+10
console.log(`success,成功的回调:${result}`)
return result
},
error=>{//失败的回调
let err = error
console.log(`error,失败的回调:${err}`)
return error
}
复制代码
中抛出一个错误 上代码:
function foo_(num){
return new Promise((res,rej)=>{//首先new一个promise 这个promise实例是必需要返回(return)的,否则将没法将这个数据吐出去
setTimeout(()=>{
try{
const a = num+1
//a = 1
res(a)//将正确的数据返出去 能够用.then接
}catch(e){
rej(e)//将错误的数据返出去 能够用.then接
}
})
})
};
foo_(100).then(
success=>{//成功的回调
let result = success+10
console.log(`success,成功的回调:${result}`)
throw new Error( result)
},
error=>{//失败的回调
let err = error
console.log(`error,失败的回调:${err}`)
return error
}
).then(
success=>{
let res = baz(success)
console.log(`res=${res}`)
},
error=>{
console.log(`这是一个错误:${error}`)
}
)
复制代码
若是咱们这么写呢?
function foo_(num){
return new Promise((res,rej)=>{
setTimeout(()=>{
try{
const a = num+1
a = 1
res(a)//将正确的数据返出去 能够用.then接
}catch(e){
rej(e)//将错误的数据返出去 能够用.then接
}
})
})
};
foo_(100).then(
success=>{//成功的回调
let result = success+10
console.log(`success,成功的回调:${result}`)
throw new Error( result)
},
error=>{//失败的回调
let err = error
console.log(`error,失败的回调:${err}`)
throw new Error( '接住了 没有注释掉 a= 1 的错误')
}
).then(
success=>{
let res = baz(success)
console.log(`res=${res}`)
},
error=>{
console.log(`这是一个错误:${error}`)
}
)
复制代码
在.then中,return 或者 throw 抛出去的值都必须是promise 只有这样才能够继续被下一个.then 中接到,至于进成功回调仍是失败回调 那就看上一个函数的执行结果了,在同步函数中,默认return throw 抛出去的值都是promise,可是若是在.then中有异步操做就必须给想办法抛出去一个promise 否则是接不到的 可是若是在.then当中没有使用return 或者 throw 出一个promise 的话,那么在下一个.then中是不会接到这个值的,而且若是是异步。我以为这个能够被称为异步的传染性
刚才咱们在.then中一直演示的是同步操做,若是.then中有异步操做,可不能够继续传递数据呢?固然是能够的!!话很少说,直接上代码。
function foo_(num){
return new Promise((res,rej)=>{
setTimeout(()=>{
try{
const a = num+1
res(a)//将正确的数据返出去 能够用.then接
}catch(e){
rej(e)//将错误的数据返出去 能够用.then接
}
},2000)
})
};
foo_(100).then(
success=>{//成功的回调
setTimeout(()=>{
let result = success+10
return result
},2000)
},
error=>{//失败的回调
let err = error
console.log(`error,失败的回调:${err}`)
throw new Error( '接住了 没有注释掉 a= 1 的错误')
}
).then(
success=>{
setTimeout(()=>{
return success+10
},2000)
},
error=>{
console.log(`这是一个错误:${error}`)
}
).then((res)=>{
console.log('6秒以后:',res)
return res
})
复制代码
打印结果:
foo_(100).then(
success=>{//成功的回调
return new Promise((res,rej)=>{
setTimeout(()=>{
let value = success+10
res(value)
},2000)
})
}
).then(
success=>{
return new Promise((res,rej)=>{
setTimeout(()=>{
res(success)
},2000)
})
}
).then((res)=>{
console.log('6秒以后:',res)
return res
})
复制代码
打印结果:
function foo(){
return Promise.resolve(100)
};
foo().then((v)=>{
return new Promise((res=>{
setTimeout(()=>{
res(v+100) //异步操做,返回promise实例利用res()传递结果
},3000)
}))
}).then((v)=>{
v=v+100
return v //同步操做,默认返回promise传递结果
}).then((v)=>{
return new Promise((res)=>{
setTimeout(()=>{
res(v+100) //异步操做,返回promise实例利用res()传递结果
},3000)
})
}).then((v)=>{
return v+100 //同步操做,默认返回promise传递结果
}).then((v)=>{
return new Promise((res)=>{
setTimeout(()=>{
res(v+100) //同步操做,默认返回promise传递结果
})
})
}).then((v)=>{
console.log(v+100)
return v+100 //同步操做,默认返回promise传递结果
}).then((v)=>{
//由于没有return 因此下面接到的v是undefind
}).then((v)=>{
console.log(v)
return v
})
复制代码
打印结果我就不贴了,看官们本身复制粘贴一下跑一下就晓得了。
再来一个混合了error状况的状况:
foo().then((v)=>{
return new Promise((res=>{
setTimeout(()=>{
res(v+100)
},3000)
}))
}).then((v)=>{
v=v+100
return v
}).then((v)=>{
return new Promise((res)=>{
setTimeout(()=>{
res(v+100)
},3000)
})
}).then((v)=>{
return v+100
}).then((v)=>{
return new Promise((res)=>{
setTimeout(()=>{
res(v+100)
})
})
}).then((v)=>{
return v+100
}).then((v)=>{
throw (v+100) //此处为error回调
}).then((v)=>{
console.log('this is resolve' ,v+100) //不会被打印
return v+100
},(e)=>{
console.log('this is error',e+100)
return e+100
}).then((v)=>{
console.log('this is v' ,v+100)
return v+100
})
复制代码
简单的总结一下:
一个异步函数中,new Promise 并将这个promise返回(return):
function foo(){
return new Promise()
//return Promise.resolve().
}
new promise时 向该构造函数内传一个函数,该函数接受两个参数:
表示成功返回的 res 相似 return
表示失败的失败返回 rej 相似 throw
function foo(){
return new Promise((res,rej)=>{
})
}
在这个函数中进行异步操做,成功的值用res(result)抛出去,相似 return result
错误的值用rej(error)抛出去 相似 throw error
function foo(num){
return new Promise((res,rej)=>{
setTimeout(()=>{
try{
const a = num+1
//a = 1
res(a)
}catch(e){
rej(e)
}
})
})
};
使用 .then 去接 foo 抛出去的值
.then 接受两个参数,即成功的回调,失败的回调
foo(100).then(
success=>{//成功的回调
console.log(`success,成功的回调:${success}`)
},
error=>{//失败的回调
console.log(`error,失败的回调:${error}`)
}
)
复制代码
关于promise,其实还有.catch,promise.all()等函数。 要再说下去就太多了,若是各位有兴趣的话,我会在后面继续介绍.catch promise.all 等一系列promise衍生出来的东西。 第一次写东西,可能写的不太好,请你们见谅~