Node的产生,大大推进了Javascript这门语言在服务端的发展,使得前端人员能够以很低的门槛转向后端开发。前端
固然,这并不表明迸发成了全栈。全栈的技能很集中,毫不仅仅是前端会写一些HTML和一些交互,后台熟悉数据库的增删查改。web
想必接触过Node的人都知道,Node是以异步(Async)回调著称的,其异步性提升了程序的执行效率,但同时也减小了程序的可读性。若是咱们有几个异步操做,而且后一个操做须要前一个操做返回的数据才能执行,这样按照Node的通常执行规律,要实现有序的异步操做,一般是一层加一层嵌套下去。数据库
为了解决这个问题,ES6提出了Promise的实现。编程
含义 Promise 对象用于一个异步操做的最终完成(或失败)及其结果值的表示。简单点说,它就是用于处理异步操做的,异步处理成功了就执行成功的操做,异步处理失败了就捕获错误或者中止后续操做。后端
它的通常表示形式为:设计模式
new Promise(
/* executor */
function(resolve, reject) {
if (/* success */) {
// ...执行代码
resolve();
} else { /* fail */
// ...执行代码
reject();
}
}
);
复制代码
其中,Promise中的参数executor是一个执行器函数,它有两个参数resolve和reject。它内部一般有一些异步操做,若是异步操做成功,则能够调用resolve()来将该实例的状态置为fulfilled,即已完成的,若是一旦失败,能够调用reject()来将该实例的状态置为rejected,即失败的。数组
咱们能够把Promise对象当作是一条工厂的流水线,对于流水线来讲,从它的工做职能上看,它只有三种状态,一个是初始状态(刚开机的时候),一个是加工产品成功,一个是加工产品失败(出现了某些故障)。一样对于Promise对象来讲,它也有三种状态:promise
pending 初始状态,也称为未定状态,就是初始化Promise时,调用executor执行器函数后的状态。 fulfilled 完成状态,意味着异步操做成功。 rejected 失败状态,意味着异步操做失败。 它只有两种状态能够转化,即并发
操做成功 pending -> fulfilled 操做失败 pending -> rejected 而且这个状态转化是单向的,不可逆转,已经肯定的状态(fulfilled/rejected)没法转回初始状态(pending)。异步
方法 Promise.prototype.then() Promise对象含有then方法,then()调用后返回一个Promise对象,意味着实例化后的Promise对象能够进行链式调用,并且这个then()方法能够接收两个函数,一个是处理成功后的函数,一个是处理错误结果的函数。
以下:
var promise1 = new Promise(function(resolve, reject) {
// 2秒后置为接收状态
setTimeout(function() {
resolve('success');
}, 2000);
});
promise1.then(function(data) {
console.log(data); // success
}, function(err) {
console.log(err); // 不执行
}).then(function(data) {
// 上一步的then()方法没有返回值
console.log('链式调用:' + data); // 链式调用:undefined
}).then(function(data) {
// ....
});
复制代码
在这里咱们主要关注promise1.then()方法调用后返回的Promise对象的状态,是pending仍是fulfilled,或者是rejected?
返回的这个Promise对象的状态主要是根据promise1.then()方法返回的值,大体分为如下几种状况:
若是then()方法中返回了一个参数值,那么返回的Promise将会变成接收状态。 若是then()方法中抛出了一个异常,那么返回的Promise将会变成拒绝状态。 若是then()方法调用resolve()方法,那么返回的Promise将会变成接收状态。 若是then()方法调用reject()方法,那么返回的Promise将会变成拒绝状态。 若是then()方法返回了一个未知状态(pending)的Promise新实例,那么返回的新Promise就是未知状态。 若是then()方法没有明确指定的resolve(data)/reject(data)/return data时,那么返回的新Promise就是接收状态,能够一层一层地往下传递。
转换实例以下:
var promise2 = new Promise(function(resolve, reject) {
// 2秒后置为接收状态
setTimeout(function() {
resolve('success');
}, 2000);
});
promise2
.then(function(data) {
// 上一个then()调用了resolve,置为fulfilled态
console.log('第一个then');
console.log(data);
return '2';
})
.then(function(data) {
// 此时这里的状态也是fulfilled, 由于上一步返回了2
console.log('第二个then');
console.log(data); // 2
return new Promise(function(resolve, reject) {
reject('把状态置为rejected error'); // 返回一个rejected的Promise实例
});
}, function(err) {
// error
})
.then(function(data) {
/* 这里不运行 */
console.log('第三个then');
console.log(data);
// ....
}, function(err) {
// error回调
// 此时这里的状态也是fulfilled, 由于上一步使用了reject()来返回值
console.log('出错:' + err); // 出错:把状态置为rejected error
})
.then(function(data) {
// 没有明确指定返回值,默认返回fulfilled
console.log('这里是fulfilled态');
});
复制代码
Promise.prototype.catch() catch()方法和then()方法同样,都会返回一个新的Promise对象,它主要用于捕获异步操做时出现的异常。所以,咱们一般省略then()方法的第二个参数,把错误处理控制权转交给其后面的catch()函数,以下:
var promise3 = new Promise(function(resolve, reject) {
setTimeout(function() {
reject('reject');
}, 2000);
});
promise3.then(function(data) {
console.log('这里是fulfilled状态'); // 这里不会触发
// ...
}).catch(function(err) {
// 最后的catch()方法能够捕获在这一条Promise链上的异常
console.log('出错:' + err); // 出错:reject
});
复制代码
Promise.all() Promise.all()接收一个参数,它必须是能够迭代的,好比数组。
它一般用来处理一些并发的异步操做,即它们的结果互不干扰,可是又须要异步执行。它最终只有两种状态:成功或者失败。
它的状态受参数内各个值的状态影响,即里面状态所有为fulfilled时,它才会变成fulfilled,不然变成rejected。
成功调用后返回一个数组,数组的值是有序的,即按照传入参数的数组的值操做后返回的结果。以下:
// 置为fulfilled状态的状况
var arr = [1, 2, 3];
var promises = arr.map(function(e) {
return new Promise(function(resolve, reject) {
resolve(e * 5);
});
});
Promise.all(promises).then(function(data) {
// 有序输出
console.log(data); // [5, 10, 15]
console.log(arr); // [1, 2, 3]
});
复制代码
// 置为rejected状态的状况
var arr = [1, 2, 3];
var promises2 = arr.map(function(e) {
return new Promise(function(resolve, reject) {
if (e === 3) {
reject('rejected');
}
resolve(e * 5);
});
});
Promise.all(promises2).then(function(data) {
// 这里不会执行
console.log(data);
console.log(arr);
}).catch(function(err) {
console.log(err); // rejected
});
复制代码
Promise.race() Promise.race()和Promise.all()相似,都接收一个能够迭代的参数,可是不一样之处是Promise.race()的状态变化不是所有受参数内的状态影响,一旦参数内有一个值的状态发生的改变,那么该Promise的状态就是改变的状态。就跟race单词的字面意思同样,谁跑的快谁赢。以下:
var p1 = new Promise(function(resolve, reject) {
setTimeout(resolve, 300, 'p1 doned');
});
var p2 = new Promise(function(resolve, reject) {
setTimeout(resolve, 50, 'p2 doned');
});
var p3 = new Promise(function(resolve, reject) {
setTimeout(reject, 100, 'p3 rejected');
});
Promise.race([p1, p2, p3]).then(function(data) {
// 显然p2更快,因此状态变成了fulfilled
// 若是p3更快,那么状态就会变成rejected
console.log(data); // p2 doned
}).catch(function(err) {
console.log(err); // 不执行
});
复制代码
Promise.resolve() Promise.resolve()接受一个参数值,能够是普通的值,具备then()方法的对象和Promise实例。正常状况下,它返回一个Promise对象,状态为fulfilled。可是,当解析时发生错误时,返回的Promise对象将会置为rejected态。以下:
// 参数为普通值
var p4 = Promise.resolve(5);
p4.then(function(data) {
console.log(data); // 5
});
// 参数为含有then()方法的对象
var obj = {
then: function() {
console.log('obj 里面的then()方法');
}
};
var p5 = Promise.resolve(obj);
p5.then(function(data) {
// 这里的值时obj方法里面返回的值
console.log(data); // obj 里面的then()方法
});
// 参数为Promise实例
var p6 = Promise.resolve(7);
var p7 = Promise.resolve(p6);
p7.then(function(data) {
// 这里的值时Promise实例返回的值
console.log(data); // 7
});
// 参数为Promise实例,但参数是rejected态
var p8 = Promise.reject(8);
var p9 = Promise.resolve(p8);
p9.then(function(data) {
// 这里的值时Promise实例返回的值
console.log('fulfilled:'+ data); // 不执行
}).catch(function(err) {
console.log('rejected:' + err); // rejected: 8
});
复制代码
Promise.reject() Promise.reject()和Promise.resolve()正好相反,它接收一个参数值reason,即发生异常的缘由。此时返回的Promise对象将会置为rejected态。以下:
var p10 = Promise.reject('手动拒绝');
p10.then(function(data) {
console.log(data); // 这里不会执行,由于是rejected态
}).catch(function(err) {
console.log(err); // 手动拒绝
}).then(function(data) {
// 不受上一级影响
console.log('状态:fulfilled'); // 状态:fulfilled
});
复制代码
总之,除非Promise.then()方法内部抛出异常或者是明确置为rejected态,不然它返回的Promise的状态都是fulfilled态,即完成态,而且它的状态不受它的上一级的状态的影响。
总结 大概经常使用的方法就写那么多,剩下的看本身实际须要再去了解。
解决Node回调地狱的不止有Promise,还有Generator和ES7提出的Async实现。
这里推荐一下个人前端学习交流群:784783012,里面都是学习前端的,若是你想制做酷炫的网页,想学习编程。本身整理了一份2018最全面前端学习资料,从最基础的HTML+CSS+JS【炫酷特效,游戏,插件封装,设计模式】到移动端HTML5的项目实战的学习资料都有整理,送给每一位前端小伙伴,有想学习web前端的,或是转行,或是大学生,还有工做中想提高本身能力的,正在学习的小伙伴欢迎加入学习。
点击:加入