在es6中,提出promise这个概念。
下面我们用这个概念来解决上文提到的回调地狱的问题.
先封装一个函数:
function loadImageAsync(url) {
return new Promise(function(resolve, reject) {
var image = new Image();
image.onload = function() {
resolve(image);
};
image.onerror = function() {
reject(new Error('Could not load image at ' + url));
};
image.src = url;
});
}
调用这个函数这后,会得到一个promise对象,然后就可以继续调用then方法。使用示例:
let imgUrls = [
"http://img.ivsky.com/img/tupian/pre/201708/18/zhuangguanmeilidetitiantupian.jpg",
"http://www-31.ibm.com/ibm/cn/youibm/img/800x450_v3.jpg",
"https://i1.mifile.cn/a4/xmad_15076870727128_IHkdK.jpg",
"http://image.beekka.com/blog/2014/bg2014100801.jpg?_=6170504",
"https://raw.github.com/think2011/ES7-Async-Await-Demo/master/app-demo.gif"
];
loadImageAsync(imgUrls[0]).then(function(d){
console.info('第1张加载成功');
console.info(d);//
}
如果你希望一张图片加载成功之后,继续加载下一张,则可以这样写代码;
loadImageAsync(imgUrls[0]).then(function(d){
console.info(d);
}).then(function(){
return loadImageAsync(imgUrls[1]); //【1】 注意这里有一个return
}).then(function(d){
console.info(d);
}).then(function(){
return loadImageAsync(imgUrls[2]);
}).then(function(d){
console.info(d);
}).then(function(){
return loadImageAsync(imgUrls[3]);
}).then(function(d){
console.info(d);
}).then(function(){
console.info("全部加载完成");
})
(1)为什么可以链式调用then方法?因为then()的返回值还是一个promise对象。
(2)注意[1]处,有一个return。如果你用=>可以更进一步的简写代码。
到现在为止,我们已经没有回调地狱了,但有连串的then!
考虑到图片的地址都放在一个数组中,我们可以用循环来做。
var p = Promise.resolve();//[1]
for(let i=0; i<imgUrls.length;i++){//[2]
p = p.then(function(){
return loadImageAsync(imgUrls[i])
}).then(function(d){console.info(d)});
}
p.then(function(){//[3]
console.info("全部加载完成")
})
(1) 注意[1]处,我们调用Promise构造器的静态方法得到一个promise对象。这个promise对象的状态是resolved,所以你给它一个then,它会立即执行其中的回调函数。
(2)注意[2]处,这里用的是let,而不是var 。你知道它们有什么区别吗?
(3)注意[3]处,在整个循环结束之后,我们再去下结论:全部加载完成。
ok,promise搞定!