Promise是抽象异步处理对象以及对其进行各种操作的组件,它的功能是可以将复杂的异步处理轻松的模式化
1.new Promise(fn)返回一个Promise对象
2.在fn
中指定异步等处理
3.使用 promise.then() 实例方法,对Promise的实例对象设置其在resolve/reject时调用的回掉函数(一次调用),当然如果只想处理异常可以采用 promise.catch(onRejected)或者promise.then(undefined, onRejected)
调用asyncFunction的时候返回的是一个Promise的实例对象,所以在调用完asyncFunction的时候使用了then,设置了成功与失败时候的回掉函数
function asyncFunction() {
return new Promise(function(resolve, rejecct) {
setTimeout(function() {
resolve('Hello World');
}, 16);
});
}
asyncFunction().then(function(value) {
console.log("Fulfilled", value);
}).catch(function(error) {
console.log("error", error);
});
通过new Promise返回的Promise对象,有以下三种状态:
Fulfilled和Rejected这两个中的任一状态都可以表示为Settled(不变的)。
function getURL(url) {
return new Promise(function(resolve, reject) {
var xhr = new XMLHttpRequest();
xhr.open("get", url);
xhr.onload = function() {
if(xhr.status == 200) {
resolve(xhr.responseText);
}else {
reject("状态错误");
}
};
xhr.onerror = function() {
reject("出错");
}
xhr.send();
});
}
//https://httpbin.org/status/500
//https://httpbin.org/get
getURL('https://httpbin.org/get').then((value) => {
console.log(value);
}).catch((error) => {
console.log(error);
});
它可以认为是
new Promise(function(resolve, reject) {
resolve();
})
Promise.resolve的返回值是一个Promise对象,所以继续可以用then调用,所以Promise.resolve也可以认为是new Promise的快捷形式
Promise.resolve的另外一个作用就是将thenable对象转换为promise对象,thenable对象就是指的是一个具有.then方法的对象,这种将thenable对象转换为promise对象的机制要求thenable对象所拥有的then方法应该和Promise所拥有的then方法具有相同的功能和处理过程,再将thenabel对象转换为promise对象的时候,还会巧妙的利用thenable对象原来所具有的then方法
thenable
最简单的例子就是jQuery.ajax(),它的返回值就是thenable的,将thenable转换为Promise对象的时候,就可以调用then和catch方法
/*将thenable对象转换为Promise对象*/
var promise = Promise.resolve($.ajax('https://httpbin.org/get'));
promise.then(function(value) {
console.log(value); //jQuery ajax的返回值是一个具有.then方法的jq XHR Object对象,这个对象继承了来自Deferred Object的方法和属性
});
var ary = [1, 2, 3, 4, 5];
for(var i = 0; i < ary.length; i++) {
Promise.resolve(ary[i]).then(function(d) {
console.log(d);
});
}
输出结果为:
1 2 3 4 5
它相当于
new Promise(function(resolve, reject) {
reject(new Error("出错了"));
});
Promise保证了每次的调用都是以异步的方式进行的,所以在实际代码中不需要调用setTimeout来自己实现异步
function test() {
console.log("test-1");
return new Promise(function(resolve, reject) {
console.log("test-2");
resolve("test-test");
});
}
test().then(function(data) {
console.log(data);
}, function() {
console.log("error");
});
console.log("test-outer");
结果:
test-1
test-2
test-outer
test-test
promise.then(function taskA(value) {
//task A
}).then(function taskB(value) {
//task B
}).then(function taskC(value) {
//task C
}).catch(function onRejected(error) {
console.log(error);
});
在每一个task的方法中,都可以包含一个return
语句,返回的值也可以是一个Promise对象,return
的值会Promise.resolve(return的返回值);进行相应的包装处理,因此不管回掉函数中返回一个怎样的值最终then
的结果都是返回一个新创建的promise对象
调用catch的时候,只是promise.then(undefined, onRejected)方法的一个别名而已,这个方法用来注册当promise对象状态变为Rejected时的回掉函数
then和catch的处理错误的区别:
总结:
1. 使用 promise.then(onFulfilled, onRejected) 的话
• 在 onFulfilled 中发生异常的话,在 onRejected 中是捕获不到这个异常的。
2. 在 promise.then(onFulfilled).catch(onRejected) 的情况下
• then 中产生的异常能在 .catch 中捕获
3. .then 和 .catch 在本质上是没有区别的
• 需要分场合使用。
Promise.all
接收一个Promise对象的数组作为参数,当这个数组的所有Promise对象全部变为resolve或reject的时候,它才回去调用.then方法
function getURL(URL) {
return new Promise(function(resolve, reject) {
var req = new XMLHttpRequest();
req.open("Get", URL, true);
req.onload = function() {
if (req.status === 200) {
resolve(req.responseText);
}else {
reject(new Error(req.statusText));
}
};
req.onerror = function() {
reject(new Error(req.statusText));
};
req.send();
});
}
var request = {
comment : function getComment() {
return getURL('https://azu.github.io/promises-book/json/comment.json').then(JSON.parse);
},
people: function getPeople() {
return getURL('https://azu.github.io/promises-book/json/people.json').then(JSON.parse);
}
};
function main() {
return Promise.all([request.comment(), request.people()]);
}
main().then(function(value) {
console.log(value);
}).catch(function(error) {
console.log(error);
});
Promise.all([request.comment(), request.people()])
会同时开始执行,而且每个promise
的结果(resolve或者reject时传递的参数值),和传递给Promise.all
的promise
数组的顺序是一致的,也就说这里面的then
中的value的值,也是是得到的两个JSON对象也是按照[comment,people]的进行排列的
所以传递给Promise.all
的Promise
不是一个个顺序执行的,而是同时开始的并行完成的
Promise.race
使用的方法和Promise.all
一样对多个Promise对象
进行并行处理,但是Promise.all在接收到所有的对象的状态都变成FullFilled
或者Reject
状态之后才会进行相应的处理,与之相对的是Promise.race
只要有一个promise对象进入FulFilled状态或者Rejected状态的话,就会进行后面的处理
function tst1() {
return new Promise(function(resolve, rejecct) {
resolve(20);
});
}
function tst2() {
return new Promise(function(resolve, rejecct) {
resolve(88);
})
};
Promise.race([tst1(), tst2()]).then(function(data) {
console.log(data);
});
输出的结果:
20
function timerPromisefy(delay) {
return new Promise(function(resolve) {
setTimeout(function() {
resolve(delay);
}, delay);
});
}
Promise.race([timerPromisefy(1), timerPromisefy(32), timerPromisefy(64), timerPromisefy(128)]).then(function(data) {
console.log(data);
});
输出的结果:
1
换成下面的这样:
Promise.all([timerPromisefy(1), timerPromisefy(32), timerPromisefy(64), timerPromisefy(128)]).then(function(data) {
console.log(data);
});
输出的结果:
[1, 32, 64, 128]
事件的注册顺序如下:
setImmediate - setTimeout - promise.then - process.nextTick
因此,我们得到了优先级关系如下:
process.nextTick > promise.then > setTimeout > setImmediate
setTimeout(function(){console.log(4)},0);
new Promise(function(resolve){
console.log(1)
for( var i=0 ; i<10000 ; i++ ){
i==9999 && resolve()
}
console.log(2)
}).then(function(){
console.log(5)
});
console.log(3);
输出结果:
1 2 3 5 4
参考:javascript-promise-book