定义:Promise 对象代表了未来将要发生的事件,用来传递异步操作的消息。(用来处理异步事件的对象)
为什么要用?
可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。
使代码更加具有可读性和可维护性,将数据请求与数据处理明确的区分开来,此外,Promise 对象提供统一的接口,使得控制异步操作更加容易。
Promise 对象有以下两个特点:
1. Promise 对象代表一个异步操作,有三种状态:Pending(进行中)、Resolved(已完成,又称 Fulfilled)和 Rejected(已失败)
只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。这也是 Promise 这个名字的由来,它的英语意思就是「承诺」,表示其他手段无法改变。
2. 一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise 对象的状态改变,只有两种可能:从 Pending 变为 Resolved 和从 Pending 变为 Rejected。
只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果。就算改变已经发生了,你再对 Promise 对象添加回调函数,也会立即得到这个结果。
这与事件(Event)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的。
例:
function fn(num) {
return new Promise(function (resolve, reject) {
if (typeof num == 'number') {
resolve();
} else {
reject();
}
}).then(function () {
console.log('参数是一个number值');
}, function () {
console.log('参数不是一个number值');
})
}
fn('hahha');
fn(1234);
//执行到resolve(),则对应执行到then方法里,两者之前可以传参
// ========
var fn = function (num) {
return new Promise(function (resolve, reject) {
if (typeof num == 'number') {
resolve(num);
} else {
reject('TypeError');
}
})
}
fn(2).then(function (num) {
console.log('first: ' + num);
return num + 1;
})
.then(function (num) {
console.log('second: ' + num);
return num + 1;
})
.then(function (num) {
console.log('third: ' + num);
return num + 1;
});
//promise最常用的用法,通过链式的写法,去维护多个异步操作的依赖关系,
// 因为.then()后也返回一个promise对象,所以可以继续用then(),
// 而且上一个then return后的值会传到下个then的参数里,这样就具备了执行下一个异步操作的前提条件。
// ========
var logging = document.getElementById('test-promise2-log');
while (logging.children.length > 1) {
logging.removeChild(logging.children[logging.children.length - 1]);
}
function log(s) {
var p = document.createElement('p');
p.innerHTML = s;
logging.appendChild(p);
}
// 0.5秒后返回input*input的计算结果:
function multiply(input) {
return new Promise(function (resolve, reject) {
log('calculating ' + input + ' x ' + input + '...')
setTimeout(resolve, 500, input * input);
});
}
// 0.5秒后返回input+input的计算结果:
function add(input) {
return new Promise(function (resolve, reject) {
log('calculating ' + input + ' + ' + input + '...');
setTimeout(resolve, 500, input + input);
});
}
var p = new Promise(function (resolve, reject) {
log('start new Promise...');
resolve(123);
});
p.then(multiply)
.then(add)
.then(multiply)
.then(add)
.then(function (result) {
log('Got value: ' + result);
});
// setTimeout方法的第三个参数会往第一个参数(函数)传参
// multiply,add都是一个promise对象,所以会接受参数传值,
// 然后通过resolve(成功后执行的方法,之前会通常会处理数据),
// 把参数值传给,promise对象(multiply,add)then方法里的参数上,
// 就这样实现了promise对象then的链式写法,也就实现了多个异步操作(有前后依赖关系)的链式写法
// ========
// ajax函数将返回Promise对象:
function ajax(method, url, data) {
var request = new XMLHttpRequest();
return new Promise(function (resolve, reject) {
request.onreadystatechange = function () {
if (request.readyState === 4) {
if (request.status === 200) {
resolve(request.responseText);
} else {
reject(request.status);
}
}
};
request.open(method, url);
request.send(data);
});
}
var logCon = document.getElementById('test-promise2-log');
var pajax = ajax('GET', '/api/categories');
pajax.then(function (text) { // 如果AJAX成功,获得响应内容
logCon.innerText = text;
}).catch(function (status) { // 如果AJAX失败,获得响应代码
logCon.innerText = 'ERROR: ' + status;
});
// ========
var p1 = new Promise(function (resolve, reject) {
setTimeout(resolve, 500, 'P1');
});
var p2 = new Promise(function (resolve, reject) {
setTimeout(resolve, 600, 'P2');
});
// 同时执行p1和p2,并在它们都完成后执行then:
Promise.all([p1, p2]).then(function (results) {
console.log(results); // 获得一个Array: ['P1', 'P2']
});
//有些时候,多个异步任务是为了容错。比如,同时向两个URL读取用户的个人信息,只需要获得先返回的
//结果即可。这种情况下,用Promise.race()实现
var p1 = new Promise(function (resolve, reject) {
setTimeout(resolve, 500, 'P1');
});
var p2 = new Promise(function (resolve, reject) {
setTimeout(resolve, 600, 'P2');
});
Promise.race([p1, p2]).then(function (result) {
console.log(result); // 'P1'
});