关于ES6中Promise的文章网上太多了,英文词义:承诺、允诺。Promise对象是一个构造函数,用来生成Promise实例。Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolve
和reject
。它们是两个函数,由JavaScript引擎提供,不用自己部署。Promise实例生成以后,可以用then
方法分别指定Resolved
状态和Reject
状态的回调函数。
什么是Promise
Promise最早由社区提出并实现,典型的一些库有Q,when, bluebird等;它们的出现是为了更好地解决JavaScript中异步编程的问题,传统的异步编程最大的特点就是地狱般的回调嵌套,一旦嵌套次数过多,就很容易使我们的代码难以理解和维护。而Promise则可以让我们通过链式调用的方法去解决回调嵌套的问题,使我们的代码更容易理解和维护,而且Promise还增加了许多有用的特性,让我们处理异步编程得心应手。如何创建Promise
ES6给我们提供了一个原生的构造函数Promise,我们可以看一下这个构造函数:// 下面的代码可以直接运行在浏览器的控制台中(Chrome浏览器)
> typeof Promise
"function" // 可以看出这是一个构造函数
> Promise
function Promise() { [native code] } // ES6的原生支持
// 我们先使用ES5的语法
var promise = new Promise(function(resolve, reject) {
var flag = Math.random();
setTimeout(function() {
if(flag) {
resolve('success');
}
else {
reject('fail');
}
}, 1000);
});
console.log(promise); // 在浏览器的控制台运行的话,它返回的是一个包含了许多属性的Promise对象;在Node.js环境中控制台输出 Promise { <pending> }。
promise.then(function(result) {
console.log(result);
}, function(err) {
console.log(err);
}); // 1s后这里的输出可能是fail也可能是success
- 因为Promise是一个构造函数,所以我们使用了new操作符来创建promise。
- 构造函数Promise的参数是一个函数(暂时叫它func),这个函数(func)有两个参数resolve和reject,它们分别是两个函数,这两个函数的作用就是将promise的状态从pending(等待)转换为resolved(已解决)或者从pending(等待)转换为rejected(已失败)。
- 创建后的promise有一些方法,then和catch。当然我们也可以人为的在Promise函数上添加一些满足我们自己需求的方法,方便每一个promise对象使用。
let p = new Promise((resolve, reject) => {
setTimeout(() => {
Math.random() > 0.5 ? resolve('success') : reject('fail');
}, 1000)
});
console.log(p);
p.then((result) => {
console.log(result);
}, (err) => {
console.log(err);
});
Promise对象的一些方法
Promise对象可以通过使用then方法将上一步返回的结果获取过来(不管是resolved还是rejected),可以通过使用catch方法捕获Promise对象在使用catch之前的异常。 首先来说一下then方法的使用:let p = new Promise((resolve, reject) => {
let flag = Math.random() > 0.5 ? true : false;
if(flag) {
console.log('使用resolve将promise状态从pending变为resolved');
resolve('success');
}
else {
console.log('使用reject将promise状态从pending变为rejected');
reject('fail');
}
});
// @1
p.then((result) => {
console.log('接受resolved的结果');
console.log(result);
}, (err) => {
console.log('捕获错误的结果');
console.log(err);
});
let p1 = new Promise((resolve, reject) => {
let flag = Math.random() > 0.5 ? true : false;
resolve();
});
// @2 使用then方法进行链式的调用
p1.then(() => {
return 1;
}).then((result) => {
console.log(result);
return 'hello'
}).then((result) => {
console.log(result);
});
// @3 在then方法内部可以再次使用异步的操作
p1.then(() => {
console.log('******');
let p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(123);
}, 1000);
});
return p1;
}).then((result) => {
console.log(result);
});
.then(null, rejection)
let p = new Promise((resolve, reject) => {
resolve();
});
p.then(() => {
console.log('progress...');
}).then(() => {
throw new Error('fail');
}).catch((err) => {
console.log(err);
});
progress...
VM141:9 Error: fail(…)
Promise的一些方法
Promise.all方法用来包装许多个Promise实例,然后组成了一个新的Promise对象,新的Promise对象的状态由前面几个被包裹的Promise对象的状态决定,如果前面的Promise都被resolve了,那么新的Promise的状态也是resolve的;只要有一个Promise被reject了,那么组成的新的Promise的状态也是reject的。 可以看下面一个例子:let arr = [1, 2, 3].map(
(value) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(value);
}, value * 1000);
});
}
);
console.log(arr);
let promises = Promise.all(arr)
.then((result) => {
console.log(result);
}).catch((err) => {
console.log(err);
});
[ Promise { <pending> },
Promise { <pending> },
Promise { <pending> } ]
[ 1, 2, 3 ] // 3s后输出的结果
let arr = [1, 2, 3].map(
(value) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(value);
}, value * 1000);
});
}
);
console.log(arr);
let promises = Promise.race(arr)
.then((result) => {
console.log(result);
}).catch((err) => {
console.log(err);
});
[ Promise { <pending> },
Promise { <pending> },
Promise { <pending> } ]
1 // 是最先改变状态的那个Promise实例resolve的值
let arr = [null, 0, 'hello',
{ then: function() { console.log(' a thenable obj')}}
];
arr.map((value) => {
return Promise.resolve(value);
});
console.log(arr);
[ null, 0, 'hello', { then: [Function: then] } ]
a thenable obj // Promise.resolve方法会将具有then方法的对象转换为一个Promise对象,然后就立即执行then方法。
let p = Promise.reject('fail');
p.catch((err) => {
console.log(err);
}); // fail