记录ES6中Promise的使用。
ES6的Promise对象使用小记。
在使用axios中,经常看到 Promise
对象,本文做个小记录。
Promise
对象用于表示一个异步操作的最终状态(完成或失败),以及该异步操作的结果值,本质上,Promise
是一个绑定了回调的对象,而不是将回调传进函数内部。
语法
1
new Promise( function(resolve, reject) {...} /* executor */ );
参数说明:
executor
是带有 resolve
和 reject
两个参数的函数 。Promise
构造函数执行时立即调用 executor
函数, resolve
和 reject
两个函数作为参数传递给 executor
(executor 函数在 Promise
构造函数返回所建 promise
实例对象前被调用)。resolve
和 reject
函数被调用时,分别将 promise
的状态改为fulfilled(完成)
或 rejected(失败)
。executor
内部通常会执行一些异步操作,一旦异步操作执行完毕(可能成功/失败),要么调用 resolve
函数来将 promise
状态改成 fulfilled
,要么调用 reject
函数将 promise
的状态改为 rejected
。如果在 executor
函数中抛出一个错误,那么该 promise
状态为 rejected
。executor
函数的返回值被忽略。
常规使用方法
resolve
1
2
3
4
5
6
7
8
var pmise = new Promise(function(resolve, reject) {
setTimeout(() => {
resolve("delay completed");
}, 500);
});
pmise.then(function(msg) {
alert(msg);
});
在500ms之后会执行alert(“deley complted”)。
reject
1
2
3
4
5
6
7
8
9
var pmise = new Promise(function(resolve, reject) {
setTimeout(() => {
reject("sorry, error occurred!");
}, 1000);
});
pmise.catch(function(error) {
alert(error);
});
catch
catch
可以指定 reject
的回调,它还有另外一个作用:在执行 resolve
的回调(也就是上面then中的第一个参数)时,如果抛出异常了(代码出错了),那么并不会报错卡死js,而是会进到这个catch
方法中。
finally
方法返回一个 Promise
,在 promise
执行结束时,无论结果是 fulfilled
或者是 rejected
,在执行 then()
和 catch()
后,都会执行 finally
指定的回调函数。这为指定执行完 promise
后,无论结果是 fulfilled
还是 rejected
都需要执行的代码提供了一种方式,避免同样的语句需要在 then()
和 catch()
中各写一次的情况。
1
2
3
4
5
6
7
8
9
10
var pmise = new Promise(function(resolve, reject) {
setTimeout(() => {
reject("sorry, error occurred!");
}, 1000);
});
pmise.then(xxx)
.catch(xxx)
.finally(() => {
//取消进度条等
})
描述
Promise
对象是一个代理对象(代理一个值),被代理的值在 Promise
对象创建时可能是未知的。它允许你为异步操作的成功和失败分别绑定相应的处理方法(handlers)。 这让异步方法可以像同步方法那样返回值,但并不是立即返回最终执行结果,而是一个能代表未来出现的结果的 promise
对象。
一个Promise
有几个状态:
- pending:初始状态,既不是成功也不是失败。
- fulfilled:意味着操作成功。
- rejected:意味着操作失败。
pending
状态的 Promise
对象可能会变为 fulfilled
状态并传递一个值给相应的状态处理方法,也可能变为失败状态(rejected
)并传递失败信息。当其中任一种情况出现时,Promise
对象的 then
方法绑定的处理方法(handlers )就会被调用(then
方法包含两个参数:onfulfilled
和 onrejected
,它们都是 Function
类型。当 Promise
状态为 fulfilled
时,调用 then
的 onfulfilled
方法,当 Promise
状态为 rejected
时,调用 then
的 onrejected
方法, 所以在异步操作的完成和绑定处理方法之间不存在竞争)。
创建Promise
Promise
对象是由关键字 new
及其构造函数来创建的。该构造函数会把一个叫做 “处理器函数”(executor function)
的函数作为它的参数。这个“处理器函数”接受两个函数—— resolve
和 reject
——作为其参数。当异步任务顺利完成且返回结果值时,会调用 resolve
函数;而当异步任务失败且返回失败原因(通常是一个错误对象)时,会调用 reject
函数。
1
2
3
4
5
6
7
let pmise = new Promise((resolve, reject) => {
// ?做一些异步操作,最终会调用下面两者之一:
//
// resolve(someValue); // fulfilled
// ?或
// reject("failure reason"); // rejected
})
结合其他函数使用:
1
2
3
4
5
6
7
8
9
function simplePromise() {
return new Promise((resolve, reject) => {
cost xhr = new XMLHttpRequest();
xhr.open("xxx");
xhr.onload = () => resolve(xhr.responseText);
xhr.onerror = () => reject(xhr.statusText);
xhr.send();
})
}
链式调用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
clickBtn() {
this.asyncA().then(obj => {
alert(obj);
return this.asyncB();
}).then(obj => {
alert(obj);
}).catch(reason => {
alert(reason);
})
},
asyncA() {
return new Promise((res, rej) => {
setTimeout(() => {
res("asyncA completed");
}, 1000);
});
},
asyncB() {
return new Promise((res, rej) => {
setTimeout(() => {
res("asyncB completed");
}, 1000);
});
}
Promise.all(iterable)
这个方法返回一个新的 promise
对象,该 promise
对象在 iterable
参数对象里所有的 promise
对象都成功的时候才会触发成功,一旦有任何一个 iterable
里面的 promise
对象失败则立即触发该 promise
对象的失败。这个新的 promise
对象在触发成功状态以后,会把一个包含 iterable
里所有 promise
返回值的数组作为成功回调的返回值,顺序跟 iterable
的顺序保持一致;如果这个新的 promise
对象触发了失败状态,它会把 iterable
里第一个触发失败的 promise
对象的错误信息作为它的失败错误信息。Promise.all 方法常被用于处理多个 promise
对象的状态集合。
此实例在 iterable
参数内所有的 promise
都“ 完成(resolved)
”或参数中不包含 promise
时回调完成(resolve
);如果参数中 promise
有一个失败(rejected
),此实例回调失败(reject
),失败原因的是第一个失败 promise
的结果。
1
2
3
4
5
6
7
8
9
var promise1 = Promise.resolve(3);
var promise2 = 42;
var promise3 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, 'foo');
});
Promise.all([promise1, promise2, promise3]).then(values => {
console.log(values);
});
输出:
Array [3, 42, “foo”]
Promise.race(iterable)
当 iterable
参数里的任意一个子 promise
被成功或失败后,父 promise
马上也会用子 promise
的成功返回值或失败详情作为参数调用父 promise
绑定的相应句柄,并返回该 promise
对象。
可以理解为一旦迭代器中的某个 promise
解决或拒绝,返回的 promise
就会解决或拒绝。
1
2
3
4
5
6
7
8
9
10
11
12
var promise1 = new Promise(function(resolve, reject) {
setTimeout(resolve, 500, 'one');
});
var promise2 = new Promise(function(resolve, reject) {
setTimeout(resolve, 100, 'two');
});
Promise.race([promise1, promise2]).then(function(value) {
console.log(value);
// Both resolve, but promise2 is faster
});
上面只会输出:
two
Promise.resolve(value)
返回一个以给定值解析后的 Promise
对象。但如果这个值是个 thenable(即带有then方法)
,返回的 promise
会“跟随”这个 thenable
的对象,采用它的最终状态(指resolved
/rejected
/pending
/settled
);如果传入的 value
本身就是 promise
对象,则该对象作为 Promise.resolve
方法的返回值返回;否则以该值为成功状态返回 promise
对象。
1
2
3
4
5
var promise1 = Promise.resolve(123);
promise1.then(value => {
console.log(value);
});
1
2
3
4
5
Promise.resolve("Success").then(value => {
console.log(value); // "Success"
}, reason => {
// 不会被调用
});
1
2
3
4
var p = Promise.resolve([1,2,3]);
p.then(v => {
console.log(v[0]); // 1
});
Resolve另一个promise对象
1
2
3
4
5
6
7
8
9
10
11
12
var original = Promise.resolve('我在第二行');
var cast = Promise.resolve(original);
cast.then(function(value) {
console.log('value: ' + value);
});
console.log('original === cast ? ' + (original === cast));
/*
* 打印顺序如下,这里有一个同步异步先后执行的区别
* original === cast ? true
* value: 我在第二行
*/
Promise.reject(reason)
该方法返回一个带有拒绝原因 reason
参数的 Promise
对象。
1
2
3
4
5
Promise.reject(new Error("fail")).then(result => {
// 未被调用
}, error => {
console.log(error); // stacktrace
});
详细说明参见Promise。