标语
平时积累的零碎的知识,要达到灵活应用的程度,还需要将其系统化。
什么是 Promise
Promise
是抽象异步处理对象及对齐做各种操作的组件。
getAsync("fileA.txt", function(error, result){
if(error){// 取得失败时的处理
throw error;
}
// 取得成功时的处理
});
Node.js
在处理异步时,回调函数中的第一个参数一定是 error
,但是怎么操作 error
并没有规范。
var promise = getAsyncPromise("fileA.txt");
promise.then(function(result){
// 获取文件内容成功时的处理
}).catch(function(error){
// 获取文件内容失败时的处理
});
Promise
对于异步处理操作和处理规则做了统一的规范,这使得我们在使用 promise
进行异步处理的时候,必须按照接口规定的方法编写处理代码。所以,基于 Promise
统一接口的做法,就可以形成基于接口的各式各样的异步处理模式,将复杂的异步处理轻松地进行模块化。
Promise 实例
Constructor
Promise
类似于 XMLHttpRequest
,从构造函数 Promise
来创建一个 promise
对象作为接口,使用 new
来实例化一个 promise
对象。
var promise = new Promise((resolve, reject) => {});
实例方法
通过 new
生成的对象为了设置其值在 resolve
(成功)/ reject
(失败)时调用的回调函数,可以使用 promise.then
实例方法。
resolve
onFullFilled
时会被调用。
reject
onRejected
时会被调用。
静态方法
对 Promise
进行操作的一些辅助方法。
Thenable
类Promise
对象。 拥有名为 .then
方法的对象。
Promise.resolve 方法可以将 thenable 对象转换为 promise 对象。
var thenable = {
then: function(resolve, reject) {
resolve(1);
}
};
Promise.resolve(thenable);
Promise.resolve
new Promise()
的快捷方式,将现有对象转换为Promise
对象;- 如果参数是
promise
实例,则直接返回这个实例 - 如果参数是
thenable
对象,则将其转换为promise
对象,并对应里面的then
方法; - 如果参数是个原始值,则返回一个
promise
对象,状态为resolved
,这个值会传递给then
方法; - 没有参数,直接返回一个状态为
resolved
的Promise
对象。
var promise = Promise.resolve(1);
这里可以认为是以下代码的语法糖:
var promise = new Promise(resolve => resolve(1));
Promise.reject
new Promise()
的快捷方式,将现有对象转换为Promise
对象;- 如果参数是
promise
实例,则直接返回这个实例 - 如果参数是
thenable
对象,则将其转换为promise
对象,并对应里面的then
方法; - 如果参数是个原始值,则返回一个
promise
对象,状态为rejected
,这个值会传递给then
方法; - 没有参数,直接返回一个状态为
rejected
的Promise
对象。
Promise.reject(new Error("出错了"))
这里可以认为是以下代码的语法糖:
var promise = new Promise((resolve, reject) => {
reject(new Error("出错了"));
});
Promise.all
- 接收一个
Promise
实例数组,或具Iterator
接口的对象; - 如果元素不是
Promise
对象,就用Promise.resolve
转换为Promise
对象; - 如果全部成功,状态变为
resolved
,返回值将组成一个数组传给回调; - 只要有一个失败,状态变为
rejected
,返回值将直接传给回调; all()
的返回值是一个新的Promise
对象。
var promises = [
new Promise(resolve => resolve(1)),
new Promise(resolve => resolve(2)),
new Promise(resolve => resolve(3))
];
Promise.all(promises).then(res => console.log(res));
// [1, 2, 3]
Promise.race
- 接收一个
Promise
实例数组,或具Iterator
接口的对象; - 如果元素不是
Promise
对象,就用Promise.resolve
转换为Promise
对象; - 只要其中有一个
Promise
实例状态发生变化(不论resolved
还是rejected),将会触发
then
方法,返回值将传给回调; race()
的返回值是一个新的 Promise 对象。
var promises = [
new Promise(resolve => resolve(1)),
new Promise((resolve, reject) => reject(new Error("出错了!"))),
new Promise(resolve => resolve(3))
];
Promise.race(promises).then(res => console.log(res));
// 1
Promise 的状态
- “has-resolution” - FullFilled
- “has-rejection” - OnRejected
- “unresolved” - Pending (初始化状态)
Promise 只能进行异步操作
为了避免同时使用同步、异步调用可能造成的混乱([详情](http://liubin.org/promises-book/#promise-is-always-async), Promise 在规范上规定只能使用异步调用方式。
Promise # then 方法
then 方法是 onFullFilled 的回调。
Promise chain
promise 可以进行链式调用。
function taskA() {
console.log("Task A");
}
function taskB() {
console.log("Task B");
}
function onRejected(error) {
console.log("Catch Error: A or B", error);
}
function finalTask() {
console.log("Final Task");
}
var promise = Promise.resolve();
promise
.then(taskA)
.then(taskB)
.catch(onRejected)
.then(finalTask);
// Task A
// Task B
// Final Task
链式调用也可以传递参数。
new Promise(resolve => resolve(1)).
then(res => res + 1)
.then(res => res + 1)
.then(res => {console.log(res)})
.catch(err => console.error(err));
// 3
Promise # catch
catch 方法是 onRejected 的回调。catch 是 promise.then(undefined, onRejected); 方法的一个别名,如果在 then 方法中存在 onRejected 函数,后面的 catch 方法不生效。
new Promise((jresolve, reject) =>{
reject(new Error("error"));
}).then(() => {}, err => {
console.log(err)
}).catch(err => {
console.error(err);
})
// Error: error
// at <anonymous>:2:12
// at new Promise (<anonymous>)
// at <anonymous>:1:1
then 和 catch 返回值
每次调用 then 和 catch 方法都会返回一个新创建的 promise 对象。
从代码上看, aPromise.then().catch() 像是针对最初的 aPromise 对象进行了一连串的方法调用,然而实际上不管是 then 还是 catch 方法调用,都返回了一个新的 promise 对象。
var aPromise = new Promise(function (resolve) {
resolve(100);
});
var thenPromise = aPromise.then(function (value) {
console.log(value);
});
var catchPromise = thenPromise.catch(function (error) {
console.error(error);
});
console.log(aPromise !== thenPromise); // => true
console.log(thenPromise !== catchPromise);// => true
===
是严格相等,所以可以判断上述三个对象都不相同,证明 then 和 catch 都返回了和调用者不同的 promise 对象。
所以,在函数调用时要注意调用的 promise 对象,否则会出现断链。
错误用法:
function asyncFunc () {
return Promise.resolve(1);
}
function badAsyncCall () {
var promise = asyncFunc();
promise.then(res => {
return 2;
});
return promise;
}
badAsyncCall().then(res => console.log(res)).catch(err => console.log(err));
// 1
badAsyncCall
方法返回的是 asyncFunc
方法中创建的对象, catch
捕获错误也是针对 asyncFunc
方法中创建的对象,中间出现了断链。
正确用法:
function asyncFunc () {
return Promise.resolve(1);
}
function anAsyncCall () {
var promise = asyncFunc();
return promise.then(res => {
return 2;
});
}
anAsyncCall().then(res => console.log(res)).catch(err => console.log(err));
// 2
then or catch?
在 then
里面使用指定错误处理函数,和使用 catch
相比有什么异同呢?
不能进行错误处理的 onRejected
function throwError (value) {
throw new Error(value);
}
// <1> onRejected不会被调用
function badMain (onRejected) {
return Promise.resolve(1).then(throwError, onRejected);
}
// <2> 有异常发生时onRejected会被调用
function goodMain (onRejected) {
return Promise.resolve(1).then(throwError).catch(onRejected);
}
badMain(function () {
console.log("bad!");
}); // 1 报错
goodMain(function () {
console.log("good");
}); // good
badMain
方法中, .then
的第二个参数中指定了用来处理错误的函数,并不能捕获第一个参数 onFullFilled
指定的函数里面出现的错误。goodMain
方法中遵循了 throwError->onRejected
的流程,这时候 throwError
中出现错误的时候, catch
能够捕捉到错误。
.then
方法中指定的 onRejected
函数所指定的回调函数,实际上针对的是其 promise
对象或之前的 promise
对象,而不是 .then
方法中指定的第一个参数( onFullFilled
所指定的对象),这就是 .then
和 catch
不同的原因。
总结
- 使用 .
then(onFullFilled, onRejected)
,在onFullFilled
中发生异常的话,onRejected
捕获不到; - 使用
.then(onFullFilled).catch(onRejected)
,在onFullFilled
中发生异常,onRejected
可以捕获到; .then
和.catch
在本质上是没有区别的,只是需要分场合使用。