探究promise
標簽:
JavaScript
前言
大家都知道Promise是ES6的一个针对回调地狱的一种解决方案,我们可以用promise去封装异步请求,用链式写法去处理复杂的业务情景,但是在一些细节问题上很容易犯一些错误
场景1:两个或N个异步请求相互依赖嵌套
如:用户页面需要进行两个请求:[请求获取用户信息],[通过这个用户的id去请求用户个人消费记录]
//用settimeout来模拟异步耗时请求function getUser(){ return new Promise((resolve, reject) => {
setTimeout(function(){
resolve({'id':1,'name':'cjt','age':24})
},1000)
})
}function getRecord(id){ return new Promise((resolve, reject) => {
setTimeout(function(){ let res = '用户id:'+id+"的记录为5条"
resolve(res)
},1000)
})
}OK,现在两个请求的异步操作我们封装好了,几种实现方式是:
//不好的方式getUser().then(user => { let id = user.id;
getRecord(id).then(res => { console.log(res)
})
})//运行结果 用户id:1的记录为5条//更好的写法getUser().then(user => { let id = user.id; return getRecord(id)
}).then(res => { console.log(res)
})//运行结果 用户id:1的记录为5条好的,解决这个问题后,如果特殊业务情况下,我想在第二个then方法中,调用第一个then的user,直接调用会报错undefined
不过按照不好的那种方式处理是可以取到user对象的,但是逻辑和嵌套多了,代码又变成了金字塔型, 无限的向右侧移动,所以这种情况的解决办法是 抛弃陈见,拥抱金字塔,但是在第一种写法的基础上,我们稍作修改
function needBoth(user,record){ let result = 'user:'+user+',record:'+record return Promise.resolve(result);
}function step1(user){ let id = user.id; return getRecord(id).then(record => { return needBoth(user,record); //需要前两个异步结果的方法
})
}
getUser()
.then(step1)
.then(result => { console.log(result)
})
//user:[object Object],record:用户id:1的记录为5条由于你的 promise 代码开始变得更加复杂,你可能发现自己开始将越来越多的函数抽离到命名函数中,我发现这样做,你的代码会越来越漂亮,就像这样:
putYourRightFootIn() .then(putYourRightFootOut) .then(putYourRightFootIn) .then(shakeItAllAbout);
这就是 promises 的重点。
场景2:等N个异步请求都成功后,再执行之后的操作
遇到这种场景我们可以使用Promise.all(), 比如下面这个文章
80%面试者都不及格的JS题
很经典的一个JS面试题
for (var i = 0; i < 5; i++) {
setTimeout(function() { console.log(new Date, i);
}, 1000);
}console.log(new Date, i);//结果://Thu Apr 19 2018 14:51:51 GMT+0800 (中国标准时间) 5//Thu Apr 19 2018 14:51:53 GMT+0800 (中国标准时间) 5//Thu Apr 19 2018 14:51:53 GMT+0800 (中国标准时间) 5//Thu Apr 19 2018 14:51:53 GMT+0800 (中国标准时间) 5//Thu Apr 19 2018 14:51:53 GMT+0800 (中国标准时间) 5//Thu Apr 19 2018 14:51:53 GMT+0800 (中国标准时间) 5原理很简单,异步事件进入task queue,先执行了for循环之后的console
for (var i = 0; i < 5; i++) {
(function(i){
setTimeout(function() { console.log(new Date, i);
}, 1000);
}(i))
}console.log(new Date, i);//结果://Thu Apr 19 2018 14:51:52 GMT+0800 (中国标准时间) 5//Thu Apr 19 2018 14:51:53 GMT+0800 (中国标准时间) 0//Thu Apr 19 2018 14:51:53 GMT+0800 (中国标准时间) 1//Thu Apr 19 2018 14:51:53 GMT+0800 (中国标准时间) 2//Thu Apr 19 2018 14:51:53 GMT+0800 (中国标准时间) 3//Thu Apr 19 2018 14:51:53 GMT+0800 (中国标准时间) 4//注意: 这里用let不行,因为let的作用于被限制到for循环中了,外部调用会报错如果我想让他输出0,1,2,3,4,5或者0->1->2->3->4->5呢?
注:0,1,2...表示同时输出,0->1->2...表示每次都间隔1秒
//0->1->2->3->4->5let task = []; //promise对象数组for (var i = 0; i < 5; i++) {
(function(j){
task.push(new Promise((resolve) => {
setTimeout(function() { console.log(new Date, j);
resolve();
}, 1000 * j);
}));
}(i))
}Promise.all(task).then(results => {
setTimeout(function(){ console.log(new Date, i);
},1000)
})
结果
Thu Apr 19 2018 15:14:02 GMT+0800 (中国标准时间) 0Thu Apr 19 2018 15:14:03 GMT+0800 (中国标准时间) 1Thu Apr 19 2018 15:14:04 GMT+0800 (中国标准时间) 2Thu Apr 19 2018 15:14:05 GMT+0800 (中国标准时间) 3Thu Apr 19 2018 15:14:06 GMT+0800 (中国标准时间) 4Thu Apr 19 2018 15:14:08 GMT+0800 (中国标准时间) 5//0,1,2,3,4,5let task = []; //promise对象数组for (var i = 0; i < 5; i++) {
(function(j){
task.push(new Promise((resolve) => {
setTimeout(function() { console.log(new Date, j);
resolve();
}, 1000);
}));
}(i))
}Promise.all(task).then(results => { console.log(new Date, i);
})
结果
Thu Apr 19 2018 15:14:02 GMT+0800 (中国标准时间) 0Thu Apr 19 2018 15:14:02 GMT+0800 (中国标准时间) 1Thu Apr 19 2018 15:14:02 GMT+0800 (中国标准时间) 2Thu Apr 19 2018 15:14:02 GMT+0800 (中国标准时间) 3Thu Apr 19 2018 15:14:02 GMT+0800 (中国标准时间) 4Thu Apr 19 2018 15:14:02 GMT+0800 (中国标准时间) 5
作者:俊滔_b059
链接:https://www.jianshu.com/p/2886b0b91975
點擊查看更多內容
為 TA 點贊
評論
評論
共同學習,寫下你的評論
評論加載中...
作者其他優質文章
正在加載中
感謝您的支持,我會繼續努力的~
掃碼打賞,你說多少就多少
贊賞金額會直接到老師賬戶
支付方式
打開微信掃一掃,即可進行掃碼打賞哦