经过几天对Promise的了解,希望可以帮助到大家。
-
什么是回调地狱
说起回调地狱 首先想到的是异步
在js中我们经常会大量使用异步回调,常用的ajxa请求
来看下面这段代码:
function a(functionb(){
c(function d(){
})
})
个人会觉得这种括号里面套括号看着会很不服,使得代码看起来很混乱。
-
如何解决这种问题
在ES6中有个叫Promise,也是为了解决回调地狱这种现象
Promise的基础使用
let p = new Promise((resolve, reject) => {
console.log('promise回调函数的内部')
setTimeout(() => {
time = Date.now()
console.log('异步任务回调函数内部的结果:' + time)
return resolve(time)
// reject(new Error('出错了!'))
}, 1000)
})
console.log('promise的外部');//promise的外部
// then方法会有一个回调函数 :onfulfill
p.then((result) => {
console.log('then中获取的结果:' + result)
}, (error) => {
console.log(error)
})
-
Promise的构造函数
-
Promise可以看作是一个(异步)代码的容器, 回调函数executor会立即执行
-
可以将内部的(异步)代码的结果 传递到promise的外部
-
promise 的executor(执行函数)接收两个参数 resolve /reject, resolve作用把异步任务的正常结果传递出去, reject把异步任务错误结果传递出去
-
resolve和reject 只能被执行一次, 执行了其中一个 另外一个就不能被执行
-
resolve和reject传递出的结果, 都是通过promise实例的 then方法中的两个回调函数onfulfilled、 onrejected来接受的
-
resolve被执行, resolve会触发 onfulfilled的执行,同时resolve会把接受的参数 作为onfufilled的参数
-
reject被执行 , reject会触发 onrejected, 同时reject会把错误参数 传给 onrejected
-
这是也就是Promise的基础使用,那如何解决回调地狱呢,看下面的链式调用。
-
Promise的解决回调地狱
let p5 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('豪已下楼')
}, 2000)
})
p5.then(result => {
return new Promise((resolve, reject) => {
console.log(result);
setTimeout(() => {
//成功
// resolve('3秒去超市');
//失败
reject('被撞了')
}, 3000)
})
}).then(result => {
return new Promise((resolve, reject) => {
console.log(result);
setTimeout(() => {
resolve('花1元买铅笔');
}, 1000)
})
}).then(result => {
console.log(result);
setTimeout(() => {
console.log('回家');
}, 2000)
}).catch(error => {
return new Promise((resolve, reject) => {
console.log(error);
setTimeout(()=>{
console.log('人已经在医院');
},1000)
})
})
- 使用then方法 获取到上一步resolve返回的数据
- catch方法获取reject返回错误的数据
但是这种链式调用的方法看着又长又麻烦,所以想到了用生成器搭配着Promise来解决
-
生成器配合Promise解决回调地狱
-
看下面代码:
-
先用一个函数放入Promise实例
function PromiseMa(msg, tiem) {
return new Promise((reslove, reject) => {
setTimeout(() => {
reslove(msg)
}, tiem)
})
}
在调用Promise
function wei() {
PromiseMa('wei1秒后执行', 1000).then(result => {
console.log(result);
return PromiseMa('hao2秒后执行', 2000)
}).then(reslut => {
console.log(reslut);
return PromiseMa('shan1秒后执行', 1000)
})
}
// wei()
这种调用Promise实例好像也不是很方便
生成器调用
function* Bxiao() {
let result1 = yield PromiseMa('wei3秒后执行', 3000)
console.log(result1);
let result2 = yield PromiseMa('hao2秒后执行', 2000)
console.log(result2);
let result3 = yield PromiseMa('shan1秒后执行', 1000)
console.log(result3);
let result4 = yield PromiseMa('wei4秒后执行', 4000)
console.log(result4);
}
let it = Bxiao()
let { value, done } = it.next()
value.then(result => {
// console.log(reslut);//wei3秒后执行
it.next(result).value.then(result => it.next(result).value)
.then(result => it.next(result).value)
.then(result => it.next(result).value)
})
使用生成器调用Promise实例,但用迭代的方式还要一个一个调用,就显得很不方便,代码也很多,这样达不到我预想的想法
看下面代码
function run(gen){
let it=gen() //生成器对象
// 递归函数
function step(result){
// value必须是Premis对象
let {value,done}=it.next(result)
// 执行完跳出
if(done){
return value
}
value.then(result=>step(result))
}
step()
}
run(Bxiao)
run(function* (){
let result1=yield PromiseMa('3秒后执行',3000)
console.log(result1);
})
这样在调用迭代器中的Promise实例就显得方便一点,可以自动执行迭代器中的Promise也就解决了回调地狱的问题。
到ES7中又有了async与await的搭配使用
async function Bxiao() {
let result1 = await PromiseMa('wei3秒后执行', 3000)
console.log(result1);
let result2 = await PromiseMa('hao2秒后执行', 2000)
console.log(result2);
let result3 = await PromiseMa('shan1秒后执行', 1000)
console.log(result3);
let result4 = await PromiseMa('wei4秒后执行', 4000)
console.log(result4);
}
Bxiao()
这样看的代码就更加的简洁