https://www.cnblogs.com/lvdabao/p/es6-promise-1.html 讲得很好
一、链式操作的用法、resolve() 的用法
<script>
console.dir(Promise);
function fun0() {
var p = new Promise((resolve, reject) => {
setTimeout(() => {
console.log("执行完成任务0");
resolve('随便什么数据0')
}, 1000)
})
return p
}
function fun1() {
var p1 = new Promise((resolve, reject) => {
setTimeout(() => {
console.log("执行完成任务1");
resolve('随便什么数据1')
}, 1000)
})
return p1
}
function fun2() {
var p2 = new Promise((resolve, reject) => {
setTimeout(() => {
console.log("执行完成任务2");
resolve('随便什么数据2')
}, 1000)
})
return p2
}
function fun3() {
var p3 = new Promise((resolve, reject) => {
setTimeout(() => {
console.log("执行完成任务3-");
resolve('随便什么数据3')
}, 1000)
})
return p3
}
fun0().then((data) => {
console.log(data);
return fun1()
}).then((data) => {
console.log(data);
return fun2()
}).then((data) => {
console.log(data+`结束`);
// return fun3()
})
</script>
二、reject的用法
<script>
function getNum() {
var p = new Promise((resolve, reject) => {
setTimeout(() => {
var num = Math.ceil(Math.random() * 10) //生成1-10的随机数
num <= 5 ? resolve(num) : reject('数字不符合')
}, 500)
})
return p
}
getNum().then(
(data) => {
console.log('resolved');
console.log(data);
},
//then的第二个参数,用来指定reject的回调
(reason, data) => { //调用reject并传递一个参数,作为失败的原因。
console.log('rejected');
console.log(reason);
}
)
</script>
有两种结果:
状态置为fullfiled
或者
状态置为rejected
image.png
三、catch的用法
我们知道Promise对象实例可以共享 Promise 构造函数上的then、catch、finally等方法,catch和then的第二个参数一样,用来指定reject的回调,用法是这样:
function getNum() {
var p = new Promise((resolve, reject) => {
setTimeout(() => {
var num = Math.ceil(Math.random() * 10) ////生成1-10的随机数
num <= 5 ? resolve(num) : reject('数字不符合')
}, 500)
})
return p
}
getNum().then(
(data) => {
console.log('resolved');
console.log(data);
}
// (reason, data) => {
// console.log('rejected');
// console.log(reason);
// }
).catch(function (reason) {
console.log('rejected'); //效果和写在then的第二个参数里面一样。
console.log(reason);
})
效果和写在then的第二个参数里面一样。不过它还有另外一个作用:在执行resolve的回调(也就是上面then中的第一个参数)时,如果抛出异常了(代码出错了),那么并不会报错卡死js,而是会进到这个catch方法中。请看下面的代码:
<script>
function getNum() {
var p = new Promise((resolve, reject) => {
setTimeout(() => {
var num = Math.ceil(Math.random() * 10) ////生成1-10的随机数
num <= 5 ? resolve(num) : reject('数字不符合')
}, 500)
})
return p
}
getNum().then(
(data) => {
console.log('resolved');
console.log(data);
console.log(somedata); //此处的somedata未定义
}
// (reason, data) => {
// console.log('rejected');
// console.log(reason);
// }
).catch(function (reason) { //效果和写在then的第二个参数里面一样。
console.log('rejected');
console.log(reason);
})
</script>
image.png
也就是说进到catch方法里面去了,而且把错误原因传到了reason参数中。即便是有错误的代码也不会报错了,这与我们的try/catch语句有相同的功能。
四、all的用法
Promise的all方法提供了并行执行异步操作的能力,并且在所有异步操作执行完后才执行回调。我们仍旧使用上面定义好的fun0(), fun1(), fun2(), fun3()这四个函数,看下面的例子:
<script>
console.dir(Promise);
function fun0() {
var p = new Promise((resolve, reject) => {
setTimeout(() => {
console.log("执行完成任务0");
resolve('随便什么数据0')
}, 1000)
})
return p
}
function fun1() {
var p1 = new Promise((resolve, reject) => {
setTimeout(() => {
console.log("执行完成任务1");
resolve('随便什么数据1')
}, 1000)
})
return p1
}
function fun2() {
var p2 = new Promise((resolve, reject) => {
setTimeout(() => {
console.log("执行完成任务2");
resolve('随便什么数据2')
}, 1000)
})
return p2
}
function fun3() {
var p3 = new Promise((resolve, reject) => {
setTimeout(() => {
console.log("执行完成任务3-");
resolve('随便什么数据3')
}, 1000)
})
return p3
}
// fun0().then((data) => {
// console.log(data);
// return fun1()
// }).then((data) => {
// console.log(data);
// return fun2()
// }).then((data) => {
// console.log(data + `结束`);
// // return fun3()
// })
Promise.all([fun0(), fun1(), fun2(), fun3()]).then((results) => {
console.log(results);
})
</script>
用Promise.all来执行,all接收一个数组参数,里面的值最终都算返回Promise对象。这样,三个异步操作的并行执行的,等到它们都执行完后才会进到then里面。那么,三个异步操作返回的数据哪里去了呢?都在then里面呢,all会把所有异步操作的结果放进一个数组中传给then,就是上面的results。所以上面代码的输出结果就是:
image.png
有了all,你就可以并行执行多个异步操作,并且在一个回调中处理所有的返回数据,是不是很酷?有一个场景是很适合用这个的,一些游戏类的素材比较多的应用,打开网页时,预先加载需要用到的各种资源如图片、flash以及各种静态文件。所有的都加载完后,我们再进行页面的初始化。
五、race的用法
all方法的效果实际上是「谁跑的慢,以谁为准执行回调」,那么相对的就有另一个方法「谁跑的快,以谁为准执行回调」,这就是race方法,这个词本来就是赛跑的意思。race的用法与all一样,我们把上面fun0(), fun1(), fun2(), fun3()的延时改一下来看一下:
<script>
console.dir(Promise);
function fun0() {
var p = new Promise((resolve, reject) => {
setTimeout(() => {
console.log("执行完成任务0");
resolve('随便什么数据0')
}, 1000)
})
return p
}
function fun1() {
var p1 = new Promise((resolve, reject) => {
setTimeout(() => {
console.log("执行完成任务1");
resolve('随便什么数据1')
}, 2000)
})
return p1
}
function fun2() {
var p2 = new Promise((resolve, reject) => {
setTimeout(() => {
console.log("执行完成任务2");
resolve('随便什么数据2')
}, 3000)
})
return p2
}
function fun3() {
var p3 = new Promise((resolve, reject) => {
setTimeout(() => {
console.log("执行完成任务3-");
resolve('随便什么数据3')
}, 4000)
})
return p3
}
// fun0().then((data) => {
// console.log(data);
// return fun1()
// }).then((data) => {
// console.log(data);
// return fun2()
// }).then((data) => {
// console.log(data + `结束`);
// // return fun3()
// })
Promise.race([fun0(), fun1(), fun2(), fun3()]).then((results) => {
console.log(results);
})
image.png
你猜对了吗?不完全,是吧。在then里面的回调开始执行时,fun1(), fun2(), fun3()并没有停止,仍旧再执行。于是再过1秒后,输出了他们结束的标志。
这个race有什么用呢?使用场景还是很多的,比如我们可以用race给某个异步请求设置超时时间,并且在超时后执行相应的操作,代码如下:
<script>
//请求某个图片资源
function requestImg() {
var p = new Promise(function (resolve, reject) {
var img = new Image();
img.onload = function () {
resolve(img);
}
img.src = 'https://www.baidu.com/';
});
return p;
}
//延时函数,用于给请求计时
function timeout() {
var p = new Promise(function (resolve, reject) {
setTimeout(function () {
reject('图片请求超时');
}, 5000);
});
return p;
}
Promise
.race([requestImg(), timeout()])
.then(function (results) {
console.log(results);
})
.catch(function (reason) {
console.log(reason);
});
</script>
requestImg函数会异步请求一张图片,我把地址写为"xxxxxx",所以肯定是无法成功请求到的。timeout函数是一个延时5秒的异步操作。我们把这两个返回Promise对象的函数放进race,于是他俩就会赛跑,如果5秒之内图片请求成功了,那么遍进入then方法,执行正常的流程。如果5秒钟图片还未成功返回,那么timeout就跑赢了,则进入catch,报出“图片请求超时”的信息。运行结果如下:
image.png
六、总结
ES6 Promise的内容就这些吗?是的,能用到的基本就这些。
我怎么还见过done、finally、success、fail等,这些是啥?这些并不在Promise标准中,而是我们自己实现的语法糖。
本文中所有异步操作均以setTimeout为例子,之所以不使用ajax是为了避免引起混淆,因为谈起ajax,很多人的第一反应就是jquery的ajax,而jquery又有自己的Promise实现。如果你理解了原理,就知道使用setTimeout和使用ajax是一样的意思。说起jquery,我不得不吐槽一句,jquery的Promise实现太过垃圾,各种语法糖把人都搞蒙了,我认为Promise之所以没有全面普及和jquery有很大的关系。后面我们会细讲jquery。
关于Promise还有一些内容是需要讲的,限于篇幅,本文就只作ES6 Promise的讲解,接下来还会有大白话讲解系列:
Promise/A+规范
jquery中的Promise
敬请期待!
网友评论