Promise 对象用来进行延迟(deferred) 和 异步(asynchronous) 计算。
回调函数是JavaScript的一大特色! node.js官方的api基本都是以会回调方式传递函数返回值。习惯同步编程的对这种异步方式多少会产生水土不服,而且层层嵌套,不知不觉就建造起了一座高高的回调金字塔。针对这种普遍问题,Promise应势而生!
有以下的业务场景,从服务器中,依次请求三张图片,每次有一张图片加载完成,就打印结果。
一般正常的写法
/**
* [loadimg 加载一张图片]
* @param {[type]} url [description]
* @param {Function} callback [description]
* @return {[type]} [description]
*/
function loadimg(url, callback) {
var img = new Image();
img.src = url;
img.onload = callback;
}
//开始加载图片
loadimg("img/a.png", function() {
console.log("图片a已经加载完毕");
loadimg("img/b.png", function() {
console.log("图片b已经加载完毕");
loadimg("img/c.png", function() {
console.log("图片c已经加载完毕");
console.log("a,b,c三张图片已经完全加载完毕");
});
});
});
ps:是不是很恐怖
采用promise的写法
/**
* [loadimg 加载一张图片]
* @param {[type]} url [description]
* @param {Function} callback [description]
* @return {[type]} [description]
*/
function loadimg(url) {
return new Promise(function(resolve, reject) {
var img = new Image();
img.src = url;
img.onload = function() {
resolve();
};
});
}
//开始加载图片
loadimg("img/a.png").then(function() {
console.log("图片a已经加载完毕");
return loadimg("img/b.png");
}).then(function() {
console.log("图片b已经加载完毕");
return loadimg("img/c.png");
}).then(function() {
console.log("图片c已经加载完毕");
console.log("a,b,c三张图片已经完全加载完毕");
});
then
方法(可以说,then就是promise的核心),而且then必须返回一个promise,同一个promise的then可以调用多次,并且回调的执行顺序跟它们被定义时的顺序一致创建Promise
var promise = new Promise(function(resolve, reject) {
// 做一些异步操作的事情,在这里做了一个定时时间为1000ms的定时器任务
setTimeout(function() {
if ( /* 一切正常 */ false) {
resolve("promise worked!");
} else {
reject("promise failed");
}
}, 1000);
});
Promise 的构造器接受一个函数作为参数,它会传递给这个回调函数两个变量 resolve 和 reject。在回调函数中做一些异步操作
成功之后调用对象的then方法,该方法中有两个参数 1. resolve(val), val的返回成功的参数
否则调用 2.reject() //处理业务错误时的函数
获取异步完成后的参数
promise.then(function(val) {
// success
console.log(val);
}, function(val) {
// failure
console.log(val);
});
catch 方法是 then(null,reject)中的reject处理的替代方法,用于指定发生错误时的回调函数
ps: promise对象的错误具有冒泡性质,会一直向后传递,直到被捕获为止
在这个例子中,创建一个Promise 发出一个异常消息
var promise = new Promise(function(resolve, reject) {
// resolve("ok");
reject("false"); //发出一个错误的异常消息
});
在这里我们使用catch来捕获错误
promise.then(function(str){
console.log("正确结果"+str);
}).catch(function(str){
console.log("异常结果"+str);
});
在这里我们使用then(null,reject) 中的reject来捕获错误
promise.then(function(str) {
console.log("正确结果" + str);
}, function(str) {
console.log("异常结果" + str);
});
Promise.all方法接受一个数组作为参数,p1、p2、p3都是Promise对象的实例。(Promise.all方法的参数不一定是数组,但是必须具有iterator接口(可遍历对象接口),且返回的每个成员都是Promise实例。)
p的状态由p1、p2、p3决定,分成两种情况。
(1)只有p1、p2、p3的状态都变成fulfilled,p的状态才会变成fulfilled,此时p1、p2、p3的返回值组成一个数组,传递给p的回调函数。
(2)只要p1、p2、p3之中有一个被rejected,p的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数。
/**
* [createPromise 创建一个promise对象]
* @param {[type]} str [description]
* @return {[type]} [description]
*/
function createPromise(str) {
return new Promise(function(resolve, reject) {
setTimeout(function() {
if (true) {
resolve(str); //返回标志位
} else {
reject();
}
}, 1000);
});
}
var promise1 = createPromise("p1"),
promise2 = createPromise("p2"),
promise3 = createPromise("p3");
//通过all方法将三个promise实例包装成新的promise实例
var promise = Promise.all([promise1, promise2, promise3]);
promise.then(function(results) {
console.log(results); // ["p1", "p2", "p3"]
});
只要p1、p2、p3之中有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的Promise实例的返回值,就传递给p的返回值。
/**
* [createPromise 创建一个promise对象,通过传入不同的时间,来区别回调的时间]
* @param {[type]} str [description]
* @param {[type]} second [description]
* @return {[type]} [description]
*/
function createPromise(str, second) {
return new Promise(function(resolve, reject) {
setTimeout(function() {
if (true) {
resolve(str); //返回标志位
} else {
reject();
}
}, second);
});
}
var promise1 = createPromise("p1", 5000),
promise2 = createPromise("p2", 1000),
promise3 = createPromise("p3", 2000);
//通过race方法将三个promise实例包装成新的promise实例
var promise = Promise.race([promise1, promise2, promise3]);
promise.then(function(results) {
console.log(results); // "p2"
});
有时需要将现有对象转为Promise对象,我们可以这样做
var p = Promise.resolve('this is promise');
下面的代码生成一个新的Promise对象的实例p,它的状态为fulfilled/rejected,所以回调函数会立即执行,Promise.resolve方法的参数就是回调函数的参数。
如果Promise.resolve方法的参数是一个Promise对象的实例,则会被原封不动地返回。
Promise.reject(reason)方法也会返回一个新的Promise实例,该实例的状态为rejected。Promise.reject方法的参数reason,会被传递给实例的回调函数。
var p = Promise.resolve('this is promise');
var p = Promise.reject('the promise is error');
p.then(function(result) {
console.log(result); //捕获正常结果
}).catch(function(result) {
console.log(result); //捕获错误结果
});
在html中引入
<script src="https://www.promisejs.org/polyfills/promise-7.0.4.min.js">script>