
本文主要是简单介绍下Promise及使用,如有错误,欢迎指正,这厢有礼了!
什么是Promise
Promise是ES6新增的一个特征,它已被列入ES6的正式规范中。
万物生必有因,Promise的产生有以下三个原因。
1. 解决回调地狱问题(回调函数多层嵌套,此处不贴代码了)。
2. 可以进行链式调用(通过then,后续详解then)。
p.then((data)=> {
console.log(1);
},(err)=> {
console.log(2);
}).then((data)=>{
console.log('成功态');
},(err)=>{
console.log('失败态');
});
3. 解决并发异步,在同一时刻内获取的并发结果。
let fs = require("fs");
function after(times, callback) { // 可以缓存函数,当条件达到时---本函数缓存了times的值
let arr = [];
return function (data) {
arr.push(data);
if (--times === 0) {
// 当执行两次后进入本方法
callback(arr);
}
}
}
// 本方法在同一时刻打印出 两个异步并发的结果。
let out = after(2,function(arr){
console.log(arr);
});
fs.readFile('./2.txt','utf8',function(err,data){out(data)});
fs.readFile('./2.txt','utf8',function(err,data){out(data)});
Promise 的三个状态
- resolved(成功态)
- rejected(失败态)
- pending (初始状态,未完成)
备注: Promise这个名字的英语意思是承诺,表示其他手段无法改变。状态一旦从pending 状态 执行为resolved或rejected ,结果就固定了,resolved 和rejected两种状态结果不会互相转换;
配合以下(模拟Promise实现源码)代码,更容易理解,resolved和rejected两种状态不可改变的特性。
function Promise(executor) {//executor 执行器--函数
let self = this;
self.status = "pending"; // 等待状态
function resolve(value) { // 成功
if (self.status == "pending") {// 由pending 状态转为resolved
self.status = "resolved";
}
}
function reject(reason) {// 失败
if (self.status == "pending") {// 由pending 状态转为rejected
self.status = "rejected";
}
executorz(resolve, reject);
}
实例:
var p = new Promise(function (resolve, reject) {
if(/* 异步操作成功 */){
resolve(); // 此函数执行,代表由 pending 状态转为 resolved状态
} else {
reject(); // 此函数执行,代表由pending 状态转为 rejected 状态
}
});
Promise 的 then方法
使用案例:
var p = new Promise(function (resolve, reject) {
if(/* 异步操作成功 */){
resolve(value);
} else {
reject(err);
}
});
// p.then(onFulfilled,onRejected) onFulfilled参数代表成功态,onRejected代表失败态。
p.then((value)=>{
// 成功态,value是上面resolve传入的值,可能是普通值(如:1,"34"),可能是Promise对象;如果vaule是普通值,则会作为下一次then的onRejected;如果是Promise对象,需要等待返回的promise执行后的结果传递给下一次then的onFulfilled或onRejected。
}, (err)=> {
// 失败态,err是上面reject传入的值
}).then((value)=>{
// 如果第一个then 返回的是普通值(不管是成功态返回的,还是失败态返回的)都会进人当前then的成态里,
},(err)=>{
});
备注:
- then方法返回的是一个新的Promise实例(注意,不是原来那个Promise实例)。因此可以采用链式写法,即then方法后面再调用另一个then方法。
- 上面的代码使用then方法,依次指定了两个回调函数。第一个回调函数完成以后,会将返回结果作为参数,传入第二个回调函数。
- 上面代码中,第一个then方法指定的回调函数,返回的是另一个Promise对象。这时,第二个then方法指定的回调函数,就会等待这个新的Promise对象状态发生变化。如果变为resolved,就调用funcA,如果状态变为rejected,就调用funcB。
promise中的值穿透(then方法中可以什么参数都不传):
p.then().then().then((data)=>{
console.log("then的穿透效果");
// 成功态
},(err)=>{
// 失败态
console.log('err:' + err);
});
模拟then值穿透源码: Promise 的then方法是实例中的方法,所以写在Promise的prototye上。
Promise.prototype.then = (onFulfilled, onRejected)=> {
// then方法中的 成功和失败参数不传,就给默认值,实现then值穿透的关键步骤;
onFulfilled = typeof onFulfilled === "function" ? onFulfilled : (value)=> {
return value;
}
onRejected = typeof onRejected === "function" ? onRejected :(err)=> {
throw err;// 只有抛出错误才会走下一个then的失败函数
// return err; 不能这么写的原因是错误函数只要有返回值,就会走下一个then的成功函数。
}
}
promise 的catch 方法
Promise.prototype.catch 方法是由then(null,rejected)实现,专门用来指定发生错误时的回调函数。
代码一:
p.then((data)=>{
},(err)=>{
}).then(null,(err)=>{
})
代码二:
p.then((data)=>{
}).catch((err)=>{
});
*** 代码一和代码二的效果一样,实质也一样。
源码实现catch方法:
Promise.prototype.catch=(onRejected)=>{
// catch 接收的参数只用于报错。
return this.then(null, onRejected);
};
Promise 的 all方法
实例:
Promise.all([read("1.txt"), read('2.txt')]).then(([one, two]) => {
// 此处返回的是一个数组,因为all的参数的是一个数组,所以返回值也是一个数组====此处[one,two]用到了对象解构
console.log(one, two)
});
备注:
- Promise.all 方法的参数是由Promise对象组成的数组,执行后返回的依旧是promise数组。
- all方法,多个任务全部成功才算是成功,如果有一个失败了就算是失败。
- all属于promise的静态方法,所以直接放到Promise类中。
配合以下(模拟all实现源码)代码,更容易理解。
Promise.all = function (promises) {
return new Promise((resolve,reject)=>{
let arr = [];
let i = 0; // i的目的是为了保证获取全部成功,来设置的索引
function processData(index,data) {
arr[index] = data;
i++;
if (i === promises.length){
resolve(arr);
}
}
for(let i = 0;i<promises.length;i++){
promises[i].then(data=>{
processData(i,data); // 此处使用了递归
}, reject);
}
})
}
Promise 的 race 方法
实例:
Promise.race([read("1.txt"), read('2.txt')]).then(data => {
console.log(data);
}).catch(err => {
console.log(err);
});
备注:
- Promise.race方法的参数是由Promise对象组成的数组,race翻译为中文是‘赛跑’,谁最先有结果就返回谁的结果。 如果有一项任务先成功了,那就成功,如果有一项任务失败了,那就是失败。
- 返回的是布尔值。
- race属于promise的静态方法,所以直接放到Promise类中。
配合以下(模拟race实现源码)代码,更容易理解。
Promise.race = function (promises) {
return new Promise((resolve, reject) => {
for (let i = 0; i < promises.length; i++) {
promises[i].then(resolve, reject);// promise 数组中的promise对象执行,谁先resolve或者reject(有结果,不管成功或失败)Promise.all 就会返回一个以此结果为准的promise对象。
}
});
}
如果有错误,欢迎指正,时间不早了,回家做饭给媳妇赔罪去了。