1.Promise简述:
Promise对象其实是一种对于异步操作的解决方案;
MDN的解释是这样的:Promise 对象用于表示一个异步操作的最终完成 (或失败), 及其结果值。
const promise1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('foo');
}, 300);
});
promise1.then((value) => {
console.log(value);
// expected output: "foo"
});
console.log(promise1);
// expected output: [object Promise]
上面的例子主要讲述了Promise的简单用法;
2.语法
new Promise( function(resolve, reject) {...} /* executor */ );
在使用Promise对象时需要对其进行实例化,并且将一个executor函数作为参数传入。这个函数有两个参数,分别名为resolve、reject的函数。当Promise函数实例化时会立即执行executor函数, resolve 和 reject 两个函数作为参数传递给executor。当resolve函数被调用时,promise的状态改为fulfilled(完成);当reject函数被调用时,promise的状态被改为rejected(失败)。在日常使用时executor函数中经常会有一些异步操作,例如:ajax请求、fetch API等;一旦异步操作执行完毕,可能成功/失败。要么调用resolve函数将promise状态改为fulfilled(完成)、要么调用reject函数将promise状态由rejected。如果失败状态不调用reject而是直接抛出错误,那么这个promise的状态也将是rejected。
3.原理分析
Promise 对象是一个代理对象(代理一个值),被代理的值在Promise对象创建时可能是未知的。它允许你为异步操作的成功和失败分别绑定相应的处理方法(handlers)。 这让异步方法可以像同步方法那样返回值,但并不是立即返回最终执行结果,而是一个能代表未来出现的结果的promise对象。
promise的几种状态
- pending: 初始状态,既不是成功,也不是失败状态。
- fulfilled:意味着成功状态
- rejected:意味着失败状态
pending 状态的 Promise 对象可能会变为fulfilled 状态并传递一个值给相应的状态处理方法,也可能变为失败状态(rejected)并传递失败信息。当其中任一种情况出现时,Promise 对象的 then 方法绑定的处理方法(handlers )就会被调用。
注意知识点:Promise 对象的then方法包含两个参数:onfulfilled 和 onrejected,它们都是 Function 类型。当Promise状态为fulfilled时,调用 then 的 onfulfilled 方法,当Promise状态为rejected时,调用 then 的 onrejected 方法, 所以在异步操作的完成和绑定处理方法之间不存在竞争。原因:Promise.prototype.then
和 Promise.prototype.catch
方法返回promise 对象, 所以它们可以被链式调用。如下图所示,图片来自MDN。
注 settled为Promise对象处在fulfilled或rejected状态。
3.方法
Promise.all(iterable)
输入:可迭代的对象(Array
、String
等)
输出:新的Promise对象
描述:该方法iterable中所有promise都成功才会触发成功,一旦iterable中有一个失败,便会触发失败。当在触发成功状态以后,会把一个包含iterable里所有promise返回值的数组作为成功回调的返回值,顺序跟iterable的顺序保持一致。
Promise.race(iterable)
输入:可迭代的对象(Array
、String
等)
输出:iterable中任意成功/失败的子promise
描述:iterable中任意一个子promise执行成功/失败,父promise马上也会用子promise的成功返回值或失败详情作为参数调用父promise绑定的相应句柄,并返回该promise对象。
Promise.resolve(value)
输入:一个值或者一个thenable(即,带有then方法的对象)
输出:一个状态由给定value决定的Promise对象
描述:如果value是thenable(即,带有then方法的对象),返回的Promise对象的最终状态由then方法执行决定;否则的话(value为空,基本类型或者不带then方法的对象),返回的Promise对象状态为fulfilled,并且将value传递给对应的then方法。通常而言,如果你不知道一个值是否是Promise对象,使用Promise.resolve(value) 来返回一个Promise对象,这样就能将value以Promise对象形式使用。
Promise.reject(reason)
输入:失败信息reason
输出:一个状态为失败的Promise对象
描述:将给定的reason失败信息传递给对应的处理方法
4.具体使用场景
function promiseAjax(url) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.open("GET", url);
xhr.onload = () => resolve(xhr.responseText);
xhr.onerror = () => reject(xhr.statusText);
xhr.send();
});
};
上述方法封装了一个对原生ajax返回promise的支持。
当使用时可直接这样调用
let httpUrl = "http://fetchData.com/getData";
promiseAjax(httpUrl).then(res=>{
console.log(res);
})
js并没有线程等待一说,但对于其他服务端语言例如java有Thread.sleep(millis)
可以阻塞当前线程;如果想要js也实现类似与java的效果可以这样写
function sleep(millis){
return new Promise(resolve=>{
setTimeout(resolve,millis);
});
}
调用方式如下
sleep(1000).then(()=>{
/**TODO code block**/
});
下面这个例子是工作中经常使用的场景
var p1 = Promise.resolve(3);
var p2 = 1337;
var p3 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, 'foo');
});
Promise.all([p1, p2, p3]).then(values => {
console.log(values); // [3, 1337, "foo"]
});
将所有异步请求封装到Promise.all(iterable)
中,使异步执行效率大大增加;同时返回值也将可以统一管理。
注 Promise.all 的快速返回失败行为
let p1 = new Promise((resolve, reject) => {
setTimeout(resolve, 1000, 'one');
});
let p2 = new Promise((resolve, reject) => {
setTimeout(resolve, 2000, 'two');
});
let p3 = new Promise((resolve, reject) => {
setTimeout(resolve, 3000, 'three');
});
let p4 = new Promise((resolve, reject) => {
setTimeout(resolve, 4000, 'four');
});
let p5 = new Promise((resolve, reject) => {
reject('reject');
});
Promise.all([p1, p2, p3, p4, p5]).then(values => {
console.log(values);
}, reason => {
console.log(reason)
});
//From console:
//"reject"
//You can also use .catch
Promise.all([p1, p2, p3, p4, p5]).then(values => {
console.log(values);
}).catch(reason => {
console.log(reason)
});
//From console:
//"reject"
Promise.all
在任意一个传入的 promise 失败时返回失败。例如,如果你传入的 promise中,有四个 promise 在一定的时间之后调用成功函数,有一个立即调用失败函数,那么Promise.all
将立即变为失败。上面例子中用到了两种捕获错误的方式,根据第3小结的原理解释,说明这两种方式是等效的。
注Promise.all
当且仅当传入的可迭代对象为空时为同步:理解一下代码即可
var p = Promise.all([]); // will be immediately resolved
var p2 = Promise.all([1337, "hi"]); // non-promise values will be ignored, but the evaluation will be done asynchronously
console.log(p);
console.log(p2)
setTimeout(function(){
console.log('the stack is now empty');
console.log(p2);
});
// Promise { : "fulfilled", : Array[0] }
// Promise { : "pending" }
// the stack is now empty
// Promise { : "fulfilled", : Array[2] }
以上便是Promise的全部内容,关于更多关于Promise的知识可以访问
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
MDN开发人员值得信赖的官方教程,感谢MDN web docs对本教程的支持!