Promise对象用法浅解

【用法】

  • executor 函数在Promise构造函数执行时同步执行,executor 内部通常会执行一些异步操作,一旦完成,可以调用resolve函数来将promise状态改成fulfilled,或者在发生错误时将它的状态改为rejected。
  • 因为 Promise.prototype.then 和 Promise.prototype.catch 方法返回promise 对象, 所以它们可以被链式调用。
  • 对象的状态不受外界影响。Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。
  • 一旦状态改变,就不会再变,任何时候都可以得到这个结果。
    基本句法
    1
    2
    3
    4
    5
    6
    7

    let promise = new Promise( ()=> (resolve, reject) {...} /* executor */ );
    promise.then((value)=> {
    // resolved的回调
    }, (error)=> {
    // rejected的回调
    });

例1

1
2
3
4
5
6

new Promise((resolve, reject) => {
setTimeout(resolve, 2000, 'done');
}).then((value)=>{
console.log(value); //两秒后打印 done
});

例2(ajax)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
const getJSON = (url)=> {
return new Promise((resolve, reject)=>{
const handler = () => {
if (this.readyState !== 4) {
return;
}
if (this.status === 200) {
resolve(this.response);
} else {
reject(new Error(this.statusText));
}
};
const client = new XMLHttpRequest();
client.open("GET", url);
client.onreadystatechange = handler;
client.responseType = "json";
client.setRequestHeader("Accept", "application/json");
client.send();
});
};

getJSON("/posts.json").then((res) => {
console.log('success:', res);
}, (error) => {
console.error('error', error);
});

Promise.prototype.then()

then方法的第一个参数是resolved状态的回调函数,第二个参数(可选)是rejected状态的回调函数。
then方法返回的是一个新的Promise实例(注意,不是原来那个Promise实例)。因此可以采用链式写法,即then方法后面再调用另一个then方法。

1
2
3
4
5
6
getJSON("/post/1.json").then(
post => getJSON(post.URL)
).then(
success => console.log("resolved: ", success),
error => console.log("rejected: ", error)
);

Promise.prototype.catch()

catch方法是.then(null, rejection)的别名,用于指定发生错误时的回调函数。
Promise 对象的错误具有“冒泡”性质,会一直向后传递,直到被捕获为止

1
2
3
4
5
6
getJSON('/posts.json').then((posts) => {

}).catch(function(error) {
// 处理 getJSON 和 前一个回调函数运行时发生的错误
console.log('发生错误!', error);
});

Promise.all(iterable)

  • Promise.all 方法常被用于处理多个promise对象的状态集合。
  • Promise.all 等待所有代码的完成(或第一个代码的失败)。
  • 如果iterable包含非promise值,则它们将被忽略,但仍然计入返回的promise。
  • 如果作为参数的 Promise 实例,自己定义了catch方法,那么它一旦被rejected,并不会触发Promise.all()的catch方法。

这些可能一时很难体会,看例子更直观:

1
2
3
4
5
6
7
8
9
10
let p1 = Promise.resolve(1);
let p2 = 11;
let p3 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, "aa");
});

Promise.all([p1, p2, p3]).then(values => {
console.log(values);
// [1, 11, "aa"]
});

Promise.race(iterable)

当iterable之中有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给race()回调函数。

Promise.resolve()

将现有对象转为 Promise 对象

  • 参数是一个Promise实例,原封不动地返回这个实例。
  • 参数是一个thenable对象,具有then方法的对象,转为Promise对象后就立即执行thenable对象的then方法。
  • 参数不是具有then方法的对象,或非对象,返回新的Promise对象,状态为resolved。
  • 不带参数,如果只为了异步
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    let thenable = {
    then: function(resolve, reject) {
    resolve(0);
    }
    };

    let p1 = Promise.resolve(thenable);
    p1.then((value) => {
    console.log(value); // 0
    });
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 不带参数类似异步
setTimeout(()=> {
console.log('three');
}, 0);

Promise.resolve().then(()=> {
console.log('two');
});

console.log('one');

// one
// two
// three

Promise.reject()

也会返回一个新的Promise实例,reject()方法的参数,会原封不动地作为reject的理由,变成后续方法的参数

【扩展】

done()

done方法,总是处于回调链的尾端,保证抛出任何可能出现的错误。

1
2
3
4
5
6
7
8
9
10
11
12
13
Promise.prototype.done = (onFulfilled, onRejected) => {
this.then(onFulfilled, onRejected)
.catch((reason) => {
// 抛出一个全局错误
setTimeout(() => { throw reason }, 0);
});
};

textFn()
.then(f1)
.catch(r1)
.then(f2)
.done();

finally()

finally方法用于指定不管 Promise 对象最后状态如何,都会执行的操作。

1
2
3
4
5
6
7
Promise.prototype.finally = (callback) => {
let p = this.constructor;
return this.then(
value => p.resolve(callback()).then(() => value),
reason => p.resolve(callback()).then(() => { throw reason })
);
};

参考