参考
https://pouchdb.com/2015/05/1...
https://developer.mozilla.org...
http://es6.ruanyifeng.com/#do...
Promises
是一种编写异步代码的方法。
Promise 对象
用于表示一个异步操作的最终状态(完成或失败),以及该异步操作的结果值。
Promise 使用
Promise适用于这样的场景,后面的操作必须根据前面的操作的结果做出相应的反应。 那么后面的操作必须等前面的操作完成并且获得前面操作的结果。
假设我们现在有三个操作doSomethingFirst,doSomethingSecond 和finalHandler。
doSomethingSecond 需要根据 doSomethingFirst 的结果做出反应
finalHandler 需要根据 doSomethingSecond 的结果做出反应
流程如下:
//resOfDoSomethingFirst 是 DoSomethingFirst的结果
doSomethingFirst
|-----------------|
doSomethingSecond(resOfDoSomethingFirst)
|------------------|
finalHandler(doSomethingSecond的结果)
|------------------|
实现这个场景需要解决以下两个问题:
后面的操作 如何知道 前面的操作 完成了
后面的操作 如何知道 前面的操作 的执行结果是什么
//包装第一个操作在 doSomethingFirst 中
const doSomethingFirst = new Promise(function(resolve, reject) {
// ... some code
if (/*操作成功 */){
resolve(doSomethingFirstValue); //将doSomethingFirst对象的状态从“pending”变为“resolved”
} else {
reject(doSomethingFirstError);
}
});
//包装第二个操作在
doSdoSomethingSecond(resOfDoSomethingFirst) {
// ... some code
return somePromise(); //返回一个promise 对象
});
//整个操作流程如下:
doSomethingFirst()
.then(doSdoSomethingSecond)
.then(finalHandler)
.catch(function (err) {
console.log(err);
})
.finally(() => {···});
通过new Promise创建的Promise 实例doSomethingFirst 有以下方法:
Promise.all(iterable)
Promise.race(iterable)
Promise.reject(reason)
Promise.resolve(value)
Promise.prototype.catch(onRejected)
Promise.prototype.then(onFulfilled, onRejected)
Promise.prototype.finally(onFinally)
1. doSomethingSecond 如何知道 doSomethingFirst 操作完成了
通过doSomethingFirst状态的变更通知。
一个 Promise有以下几种状态:
pending: 操作未完成。
fulfilled: 操作完成,并且成功。
rejected: 操作完成,但是失败。
resolve()函数:
在异步操作成功时调用
作用是:将Promise对象的状态从 pending 变为 fulfilled,并将异步操作的结果,作为参数传递出去;
reject()函数:
在异步操作失败时调用
作用是:将Promise对象的状态从 pending 变为 rejected, 并将异步操作的错误,作为参数传递出去。
当操作完成时(Promise对象的状态变为fulfilled 或 rejected时),doSomethingFirst 就会通过then()函数调用doSomethingSecond,doSomethingSecond就知道doSomethingFirst已经完成了。
2. doSomethingSecond 如何知道 doSomethingFirst 的执行结果是什么
doSomethingFirst通过给then()函数调用doSomethingSecond(resOfDoSomethingFirst)并把执行结果resOfDoSomethingFirst作为参数传递给doSomethingSecond
Promise.prototype.then(onFulfilled, onRejected)
用于为 Promise 实例添加状态改变时的回调函数
返回值:一个新的 Promise,所可以采用链式写法,then()函数后面再调用then()函数
参数:
onFulfilled
是一个函数,有一个参数,用来记录变成fulfilled状态返回的结果
当doSomethingFirst这个Promise的状态变成fulfilled 时,onFulfilled作为回调函数被调用
onRejected
是一个函数,有一个参数,用来记录变成rejected状态返回的原因
当doSomethingFirst这个Promise的状态变成rejected 时,onRejected作为回调函数被调用
在当前的例子里参数onFulfilled就是doSomethingSecond(resOfDoSomethingFirst),resOfDoSomethingFirst 记录了doSomethingFirst 变成fulfilled状态返回的结果。
注意事项:
当给then()传入的参数不是函数时,它实际上将其解释为then(null),将使先前的Promise的结果落空
Promise.resolve('foo').then(Promise.resolve('bar')).then(function (result) {
console.log(result); // foo
});
等价于
Promise.resolve('foo').then(null).then(function (result) {
console.log(result);// foo
});
上面的代码并没有按照我们期望的打印"bar", 而是打印"foo"
正确的写法是:
Promise.resolve('foo').then(function () {
return Promise.resolve('bar');
}).then(function (result) {
console.log(result); // bar
});
给then()传入的参数是函数时,函数的内部我们可以做以下三件事:
1. 返回另外一个promise
2. 返回一个同步值
3. 抛出一个同步错误
示例:返回另外一个promise
doSomethingFirst()
.then(doSdoSomethingSecond)
.then(finalHandler)
//somePromise() 返回promise对象
function doSomethingSecond(resOfDoSomethingFirst) {
return somePromise(); //有return, finalHandler接受到的是resOfDoSomethingSecond
//somePromise();// 没有return, finalHandler接受到的是undefined
}
function finalHandler(resOfDoSomethingSecond) {
// handle resOfDoSomethingSecond
}
示例:返回同步值 && 抛出一个同步错误
返回同步值实际上是将同步代码转换为Promisey代码的一种很棒的方法。例如,假设我们有一个用户的内存缓存。我们可以做到:
//getUserByName 和 getUserAccountById 都返回promise对象
getUserByName('nolan').then(function (user) {
if (user.isLoggedOut()) { //如果用户注销
throw new Error('user logged out!'); // 抛出一个同步错误
}
if (inMemoryCache[user.id]) {
return inMemoryCache[user.id]; // 返回一个同步值!
}
return getUserAccountById(user.id); // 返回一个promise!
}).then(function (userAccount) {
// I got a user account!
}).catch(function (err) {
// Boo, I got an error!
});
如果用户注销,catch()将收到一个同步错误;通过callbacks,这个错误会被忽略
如果任何promise被拒绝,catch()将收到一个异步错误。
通常情况下,一个promise 依赖于另一个promise ,但当我们需要两个promises的输出。我们该怎么做
getUserByName('nolan').then(function (user) {
return getUserAccountById(user.id);
}).then(function (userAccount) {
// 在这里我们已经获取到了用户账号userAccount,
// 但是我们也需要user对象时该怎么做?
});
解决方案:
function onGetUserAndUserAccount(user, userAccount) {
return doSomething(user, userAccount);
}
function onGetUser(user) {
return getUserAccountById(user.id).then(function (userAccount) {
return onGetUserAndUserAccount(user, userAccount);
});
}
getUserByName('nolan')
.then(onGetUser)
.then(function () {
// at this point, doSomething() is done, and we are back to indentation 0
});
Promise.prototype.catch(onRejected)
用于指定发生错误时的回调函数。catch 可以捕获
返回值:返回一个Promise,处理状态变为rejected的情况
参数:
onRejected
是一个函数,有一个参数,用来记录变成rejected状态返回的原因。
当promise 状态变为rejected时被调用。
注意事项:
catch(rejectHandler)
等同于
.then(null, rejectHandler)或.then(undefined, rejectHandler)
但是 then(resolveHandler).catch(rejectHandler) 和then(resolveHandler, rejectHandler)
不是完全相同的。
区别在于:当使用then(resolveHandler, rejectHandler)格式时,如果resolveHandler本身抛出了错误,那么rejecthandler实际上不会捕获错误。所以更建议使用catch 而不是then的第二个参数。
示例:
var p1 = new Promise((resolve, reject) => {
resolve('one');
});
// catch函数中可以捕捉到resolveHandler 中的error并打印
p1.then(function () {
throw new Error('oh noes');
}).catch(function (err) {
console.log('err=', err); // Error: oh noes
});
// reject函数不能捕捉到resolveHandler中的error
p1.then(function () {
throw new Error('oh noes');
}, function (err) {
console.log('err=', err);
});
Promise.prototype.finally(onFinally)
用于指定不管 Promise 对象最后状态如何,都会执行的操作
finally本质上是then方法的特例
promise
.finally(() => {
// 语句
});
// 等同于
promise
.then(
result => {
// 语句
return result;
},
error => {
// 语句
throw error;
}
);
返回值:返回一个Promise,这个Promise对象设置了 finally 回调函数
参数:Promise 结束后调用的函数,onFinally 这个函数不接收任何参数,它仅用于无论最终结果如何都要执行的情况。所以finally方法里面的操作,不应依赖于 Promise 的执行结果。
示例:
promise
.then(result => {···})
.catch(error => {···})
.finally(() => {···});
Promise.resolve(value)
用于将现有对象转为 Promise 对象
new Promise(function (resolve, reject) {
resolve(someSynchronousValue);
}).then(/* ... */);
等价于
Promise.resolve(someSynchronousValue).then(/* ... */);
返回值:返回一个Promise 对象,这个Promise对象是被给定的值解析过的。
参数:
value
将被Promise对象解析的参数
参数类型:
Promise对象
具有then方法的对象
没有then方法的对象
不带有任何参数
示例1:参数是一个Promise对象
Promise.resolve将不做任何修改、原封不动地返回这个Promise对象
var p = Promise.resolve([1,2,3]);
console.log("p=", p); //"p=" [object Promise]
console.log('p type= ', typeof(p)); // "p type= " "object"
p.then(function(v) {
console.log("v=",v); //"v=" Array [1, 2, 3]
console.log("v type=",typeof(v)); //"v type=" "object"
});
var p2 = Promise.resolve(p);
console.log("p2=", p2); //"p2=" [object Promise]
console.log('p2 type= ', typeof(p2)); //"p2 type= " "object"
p2.then(function(v) {
console.log("p2 v=",v); //"p2 v=" Array [1, 2, 3]
console.log("p2 v type=",typeof(v)); //"p2 v type=" "object"
});
p2 == p
示例2:参数是一个具有then方法的对象
返回的promise会采用这个thenable的对象的最终状态。
let thenable = {
then: function(resolve, reject) {
resolve(42);
}
};
let p = Promise.resolve(thenable);
p.then(function(value) {
console.log(value); // 42
});
Promise.resolve方法会将thenable对象转为 Promise 对象,然后就立即执行thenable对象的then方法,thenable对象的then方法执行后,对象p的状态就变为resolved,从而立即执行最后那个then方法指定的回调函数,输出 42
示例3:参数是一个没有then方法的对象
var p = Promise.resolve([1,2,3]);
console.log("p=", p); //"p=" [object Promise]
console.log('p type= ', typeof(p)); // "p type= " "object"
p.then(function(v) {
console.log("v=",v); //"v=" Array [1, 2, 3]
console.log("v type=",typeof(v)); //"v type=" "object"
});
var p = Promise.resolve(123);
console.log("p=", p); //"p=" [object Promise]
console.log('p type= ', typeof(p)); // "p type= " "object"
p.then(function(v) {
console.log("v=",v); //"v=" 123
console.log("v type=",typeof(v)); //"v type=" "number"
});
var p = Promise.resolve("123");
console.log("p=", p); //"p=" [object Promise]
console.log('p type= ', typeof(p)); // "p type= " "object"
p.then(function(v) {
console.log("v=",v); //"v=" "123"
console.log("v type=",typeof(v)); //"v type=" "string"
});
示例4:不带有任何参数
var p = Promise.resolve();
console.log("p=", p); //"p=" [object Promise]
console.log('p type= ', typeof(p)); // "p type= " "object"
p.then(function(v) {
console.log("v=",v); //"v=" undefined
console.log("v type=",typeof(v)); //"v type=" "undefined"
});
注意事项:
立即resolve()的 Promise 对象,是在本轮“事件循环”(event loop)的结束时执行,而不是在下一轮“事件循环”的开始时
//在下一轮“事件循环”开始时执行
setTimeout(function () {
console.log('three');
}, 0);
//在本轮“事件循环”结束时执行
Promise.resolve().then(function () {
console.log('two');
});
//立即执行
console.log('one');
结果:
"one"
"two"
"three"
Promise.reject(reason)
返回值:返回一个Promise 对象,这个Promise 对象 带有状态是rejected的原因
参数:
reason
表示Promise被拒绝的原因
new Promise(function (resolve, reject) {
reject(someSynchronousReson);
}).then(null,function(reason){
//...
});
等价于
Promise.reject(someSynchronousReson)
.then(null, function(reason) {
//...
});
示例:
new Promise(function (resolve, reject) {
reject("reject reason");
}).then(null,function(reason){
console.log(reason);//"reject reason"
});
Promise.reject("reject reason").then(null, function(reason) {
console.log(reason); // "reject reason"
});
Promise.reject(new Error("reject reason")).then(null, function(error) {
console.log(error); // Error: reject reason
});
注意事项:与Promise.resolve不同的是Promise.reject()方法的参数,会原封不动地作为reject的理由,变成后续方法的参数。
const thenable = {
then(resolve, reject) {
reject('出错了');
}
};
Promise.reject(thenable)
.catch(e => { //e不是reject抛出的“出错了”这个字符串,而是thenable对象。
console.log(e === thenable) // true
})
Promise.all(iterable)
用于将多个 Promise 实例,包装成一个新的 Promise 实例
返回值:返回一个新的promise对象,iterable中所有的promise都变成resolved状态时返回的 promise才会变为resolved状态; iterable中有一个promise变成rejected状态,promise就会变为rejected状态。
参数:
iterable
一个可迭代对象,eg Array 或 String
示例: iterable中所有的promise都变成resolved状态时返回的 promise才会变为resolved状态
var p1 = new Promise((resolve, reject) => {
setTimeout(resolve, 1000, 'one');
});
var p2 = new Promise((resolve, reject) => {
setTimeout(resolve, 2000, 'two');
});
var p3 = new Promise((resolve, reject) => {
setTimeout(resolve, 3000, 'three');
});
const p = Promise.all([p1, p2, p3]).then(values => {
console.log(values); //["one", "two", "three"]
}).catch(reason => {
console.log(reason); //没执行
});
流程:p创建时为pending状态,当p1, p2, p3的状态都变成resolved时触发p变成resolved状态。
p1 1s
|----------|resolved
p2 2s
|--------------------|resolved
p3 3s
|------------------------------|resolved
p resolved
示例:iterable中有一个promise变成rejected状态,promise就会变为rejected状态
var p1 = new Promise((resolve, reject) => {
setTimeout(resolve, 1000, 'one');
});
var p2 = new Promise((resolve, reject) => {
setTimeout(resolve, 2000, 'two');
});
var p3 = new Promise((resolve, reject) => {
reject('reject');
});
const p = Promise.all([p1, p2, p3]).then(values => {
console.log(values); //没执行
}).catch(reason => {
console.log(reason); //"reject"
});
流程:p创建时为pending状态,p3先执行完,p3的状态变成rejected时触发p变成rejected状态。
p1 1s
|----------|resolved
p2 2s
|--------------------|resolved
p3
|-|rejected
p rejected
示例:如果作为参数的 Promise 实例,自己定义了catch方法,那么它一旦被rejected,并不会触发Promise.all()的catch方法
var p1 = new Promise((resolve, reject) => {
setTimeout(resolve, 1000, 'one');
});
var p2 = new Promise((resolve, reject) => {
setTimeout(resolve, 2000, 'two');
});
var p3 = new Promise((resolve, reject) => {
reject('reject');
}).catch(reason => {
console.log(reason); //reject
});
const p = Promise.all([p1, p2, p3]).then(values => {
console.log(values); // ["one", "two", undefined]
}).catch(reason => {
console.log(reason); //没执行
});
流程:p创建时为pending状态,p3先执行完,p3的状态变成rejected时,调用自己定义的catch函数抛出错误,不会触发p变成rejected状态。当p1 和 p2 也执行完时,触发p变成resolved状态
p1 1s
|----------|resolved
p2 2s
|--------------------|resolved
p3
|-|rejected
|p resolved
示例:如果传入的参数是一个空的可迭代对象,则返回一个resolved状态的 Promise
const p = Promise.all([]).then(values => { //p创建时状态就为resolved
console.log(values); // []
});
Promise.race(iterable)
同样是将多个 Promise 实例,包装成一个新的 Promise 实例
返回值:返回一个新的promise对象,一旦iterable中的某个promise变为resolved或rejected状态,返回的 promise就会变为resolved或rejected状态。谁最先执行完就返回谁的状态
参数:
iterable
一个可迭代对象,eg Array 或 String
示例: 一旦iterable中的某个promise变为resolved状态,返回的 promise就会变为resolved状态。
var p1 = new Promise((resolve, reject) => {
setTimeout(resolve, 1000, 'one');
});
var p2 = new Promise((resolve, reject) => {
setTimeout(resolve, 2000, 'two');
});
var p3 = new Promise((resolve, reject) => {
setTimeout(resolve, 3000, 'three');
});
const p = Promise.race([p1, p2, p3]).then(values => {
console.log(values); //["one", "two", "three"]
}).catch(reason => {
console.log(reason); //没执行
});
流程:p创建时为pending状态,p1先执行完,p1的状态都变成resolved时触发p变成resolved状态。
p1 1s
|----------|resolved
p resolved
p2 2s
|--------------------|resolved
p3 3s
|------------------------------|resolved
示例:一旦iterable中的某个promise变为rejected状态,返回的 promise就会变为rejected状态。
var p1 = new Promise((resolve, reject) => {
setTimeout(resolve, 1000, 'one');
});
var p2 = new Promise((resolve, reject) => {
setTimeout(resolve, 2000, 'two');
});
var p3 = new Promise((resolve, reject) => {
reject('reject');
});
const p = Promise.all([p1, p2, p3]).then(values => {
console.log(values); //没执行
}).catch(reason => {
console.log(reason); //"reject"
});
流程:p创建时为pending状态,p3先执行完,p3的状态变成rejected时触发p变成rejected状态。
p1 1s
|----------|resolved
p2 2s
|--------------------|resolved
p3
|-|rejected
p rejected