像结识了一位新朋友一样,最近开始学习了promise。一开始接触到这个名词的时候也在脑海中想,promise是到底是做什么的呢。那么下面跟我一起来认识一下promise把。
首先来了解一下promise的含义
简单来说,promise是一种异步流程的控制手段,比传统的回调函数解决方案更合理和简洁。它解决了传统回调函数方式产生的回调地狱的问题。ES6将其写进了语言标准,统一了语法,原生提供了Promise。
下面我们来看一个简单的例子:
有这么一个场景,想做一道菜:首先要去买菜,买完菜之后才能洗菜,洗完菜之后才能切菜,切完之后才能炒菜,转换成js如下:
function A(callback){
setTimeout(function(){
callback("菜买好了");
}, 1000);
}
function B(callback){
setTimeout(function(){
callback("菜洗好了");
}, 2000);
}
function C(callback){
setTimeout(function(){
callback("菜切好了");
}, 3000);
}
function D(callback){
setTimeout(function(){
callback("菜炒好了");
}, 3000);
}
- 传统的回调函数方式是
A(function(res){
console.log(res);
B(function(res){
console.log(res);
C(function(res){
console.log(res);
C(function(res){
console.log(res);
console.log("菜炒好啦");
});
});
});
});
这就是传说中的回调地狱,实际的场景嵌套的层级可能还更多。这种代码非常不易于理解,而且代码难以维护。 而promise就非常适合这种场景,上面的代码用promise实现
function A() {
return new Promise(function (resolve, reject) {
setTimeout(function(){
resolve("菜买好了");
}, 1000);
});
}
function B() {
return new Promise(function (resolve, reject) {
setTimeout(function(){
resolve("菜洗好了");
}, 2000);
});
}
function C() {
return new Promise(function (resolve, reject) {
setTimeout(function(){
resolve("菜切好了");
}, 2000);
});
}
function D() {
return new Promise(function (resolve, reject) {
setTimeout(function(){
resolve("菜炒好了");
}, 2000);
});
}
A().then(function(res) {
console.log(res);
return B();
}).then(function(res) {
console.log(res);
return C();
}).then(function(res) {
console.log(res);
return D();
}).then(function(res) {
console.log(res);
console.log("菜炒好了");
});
可见Promise最大的好处是在异步执行的流程中,把执行代码和处理结果的代码清晰地分离了。
深入理解promise
Promise对象可以理解为一次将要执行的操作(常常被用于异步操作),使用了 Promise 对象之后可以用一种链式调用的方式来组织代码,让代码更加直观。promise 实现链式调用返回的并不是this而是一个新的promise。
promise(承诺)有三种状态,分别是
- resolve (成功)
- reject (失败)
- pending (等待态)
状态改变: Promise对象的状态改变,只有两种可能: 从pending变为reject。 从pending变为resolve 如果一旦promise成功了就不能失败,相反也是一样的。所以这两种情况只要发生,状态就凝固了,不会再变了,这时就称为resolved(已定型)。
每一个promise的实例上都有一个then方法,then方法中有两个参数,一个参数叫成功的函数 ,一个是失败的函数。 then方法定义:then(fulfilledAHandler, errorHandler),对应着Promise的resolve, reject。
一个promise可以then多次
let p = new Promise((resolve,reject)=>{
resolve('成功');
});
p.then(data=>{
console.log(data);
});
p.then(data=>{
console.log(data);
})
p.then(data => {
console.log(data);
});
promise中只要发生错误,就会执行失败态。如果返回的是一个普通值就会走到写一个then中的成功回调,如果有错误产生会走失败的回调。
- Promise只有一个参数 叫excutor执行器,默认new时就会调用
let p = new Promise((resolve,reject)=>{
// 默认promise中的executor是同步执行的
resolve('买');
});
// then方法是异步调用的,事件环
p.then(
(value)=>{ // value成功
console.log(1);
},
(err)=>{ // err失败
});
console.log(2);
执行结果,2 1。
promise可以处理并发任务
promise用promise.all方法做并发调用,当所有Promise 对象都变为完成态或失败态时,回调将被执行。
let fs = require('fs'); // fileSystem
function read(url) {
return new Promise((resolve, reject) => {
fs.readFile(url, 'utf8', function (err, data) {
if (err) reject(err);
resolve(data);
})
})
}
Promise.all([read('1.txt'),read('2.txt')]).then((data)=>{
console.log(data);
},err=>{
console.log(err);
});
promise.race赛跑,处理多请求只取最快的
Promise.all([read('1.txt'),read('2.txt')]).then((data)=>{
console.log(data);
},err=>{
console.log(err);
});
读取哪个文件快,返回哪个文件的结果
Promise.resolve() 返回一个成功的promise
Promise.reject() 返回一个失败的promise
promise.reject('123').then(null,data=>{
console.log(data);
});
最后用es6语法简单实现一下Promise的原理
class Promise {
constructor(executor) {
this.status = 'pending';
this.value = undefined;
this.reason = undefined;
let resolve = value => {
if (this.status ==='pending'){
this.status = 'resolved';
this.value = value;
}
}
let reject = reason => {
if (this.status === 'pending') {
this.status = 'rejected';
this.reason = reason;
}
}
try {
executor(resolve, reject);
} catch (e) {
reject(e);
}
}
then(onFufilled,onRjected){
if(this.status === 'resolved'){
onFufilled(this.value);
}
if(this.status === 'rejected'){
onRjected(this.reason);
}
}
}
module.exports = Promise