理解Promise
一、Propmise基本用法
Promise用于发送一个异步完成的结果,是替代回调函数的另一种选择。可以把Promise理解为一种异步函数。
以下函数通过一个Promise来异步地返回一个结果
function asyncFunc() {
return new Promise(
function (resolve, reject) {
···
resolve(result);
···
reject(error);
});
}
你可以这样调用它:
asyncFunc()
.then(result => { ··· })
.catch(error => { ··· });
NOTE
promise正常情况下结果只能用.then(result =>)来获取。
特殊情况下,在co工具中,使用yield可以得到Promise的结果。
1. Chaining then() calls(链式调用then)
then() 总是返回一个Promise,这使得你可以链式调用:
asyncFunc1()//----设该函数会得到一个promise P,它会resolve出来result1
.then(result1 => {
// Use result1
return asyncFunction2(); // 得到一个promise A, 它会resolve出来result2
})
.then(result2 => { //
// Use result2
})
.catch(error => {
// Handle errors of asyncFunc1() and asyncFunc2()
});
Promise P在.then()之后返回了什么东西取决于then中的函数做了什么:
- 如果then()中的函数返回的是一个Promise(如A), 则这个 Promise的resolve的结果值传递为P的resolve结果值。
- 如果then()中的函数返回了一个不同的值,则这个值会变成P的resolve值。
- 如果then()中的函数抛出了一个意外,则P会因为这个意外而被rejected。
2. Executing asynchronous functions in parallel(并行执行异步函数)
如果你通过then()链式调用Promise,它们就会按顺序执行,一个时间只执行一个Promise
如果你不这样采用链式调用,而是立即调用它们,则它们会并行执行。
而Promise.all()使得你可以一次性获得所有结果。其输入是一个由一系列Promises组成的数组,其输出是一个单个的Promise,其resolve的结果值是一个由一系列结果组成的数组。
Promise.all([
asyncFunc1(),
asyncFunc2(),
])
.then(([result1,result2]) => {
})
.catch(err => {
// Receives first rejection among the Promises
});
二、Promise对象详述
Promise对象用于表示一个异步操作的最终状态(完成或失败),以及其返回的值。
Eg:使用Promise构造函数构造一个promise对象实例:
var promise1 = new Promise(function(resolve, reject) {
setTimeout(resolve, 1000, 'foo');//即1s后执行resolve(1)
});
console.log(promise1);//Promise {<resolved>: "foo"}
Promise 对象是一个代理对象(代理一个值),被代理的值在Promise对象创建时可能是未知的。它允许你为异步操作的成功和失败分别绑定相应的处理方法。 这让异步方法可以像同步方法那样返回值,但并不是立即返回最终执行结果,而是返回一个能代表未来出现的结果的promise对象。
一个 Promise有以下几种状态:
- pending: 初始状态,既不是成功,也不是失败状态。
- fulfilled/resolved: 意味着操作成功完成。
- rejected: 意味着操作失败。
注意: 如果一个promise对象处在fulfilled或rejected状态而不是pending状态,那么它也可以被称为settled状态。你可能也会听到一个术语resolved ,它表示promise对象处于fulfilled状态。
语法
new Promise(function(resolve, reject){})
param:
- executor: TYPE function 带有resolve和reject两个参数的函数.Promise构造函数执行时立即调用executor 函数, resolve 和 reject 两个函数作为参数传递给executor(executor 函数在Promise构造函数返回新建对象前被调用)。executor 内部通常会执行一些异步操作,一旦完成,可以调用resolve函数来将promise状态改成fulfilled,或者在发生错误时将它的状态改为rejected。
三、Promise类的方法
1. Promise.all(iterable)
返回一个新的Promise实例,此实例在 iterable 参数内所有的 promise 都“完成(resolved)”或参数中不包含 promise 时回调完成(resolve);如果参数中promise有一个失败(rejected),此实例回调失败(reject),失败原因的是第一个失败的promise 的结果。
此方法在集合多个 promise 的返回结果时很有用。
语法
Promise.all(iterable)
param:
- iterable: 一个可迭代对象,如Array或String。
- 如果iterable是一个空的可迭代对象,则返回一个已完成(already resolved)状态的promise;
- 如果iterable中不包含任何promise,则返回一个异步完成(asynchronously resolved)状态的promise;
- 其他情况下返回一个处理中(pending)状态的promise。这个返回的 promise 之后会在所有的 promise 都完成或有一个 promise 失败时异步地变为完成(resolved)或失败(rejected)。
示例1:Promise.all基本用法
var p1 = Promise.resolve(3);
var p2 = 1337;
var p3 = new Promise((resolve,reject) => {
setTimeout(resolve, 1000, 'foo');
});
Promise.all([p1,p2,p3]).then(values => {
console.log(values);//1s后得到:[3, 1337, "foo"]
});
示例2:Promise.all的同步和异步情况
注意: Promise.all当且仅当传入的可迭代对象为空时为同步,其他都是异步的
var p = Promise.all([]); // will be immediately resolved
var p2 = Promise.all([1337, "hi"]); // non-promise values will be ignored, but the evaluation will be done asynchronously
console.log(p);//Promise {<resolved>: Array(0)}
console.log(p2);//Promise {<pending>}
setTimeout(function(){
console.log(p1);//Promise {<resolved>: Array(0)}
console.log(p2);//Promise {<resolved>: Array(2)}
});
示例3:Promise.all之后的链式处理
注意:如果Promise.all传入了若干个promise,如果其中有一个promise立即调用失败函数,其他promise都是在一定时间后调用成功函数,那么Promise.all将立即变为失败。
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('three reject')
});
//使用then()
Promise.all([p1,p2,p3]).then(resultArr => {
console.log(resultArr);
}, err => {
console.log(err);
});
/*控制台输出:
three reject
*/
//或者使用.then().catch()
Promise.all([p1, p2, p3]).then(resultArr => {
console.log(resultArr);
}).catch(err=> {
console.log(err);
})
2. Promise.race(iterable)
返回一个promise,一旦iterable中的某个promise变为resolved或rejected,返回的promise就变为resolved或rejected。
语法
Promise.race(iterable);
param:
- iterable:可迭代对象,类似Array,同1.Promise.all(iterable)的参数iterable
return:
一个promise对象实例,只要给定的iterable中有一个promise变为resolved或rejected,那么就采用第一个状态变为resolved或rejected的这个promise的值,从而异步地变为resolved或rejected。
示例
var p1 = new Promise(function(resolve, reject) {
setTimeout(resolve, 5000, "one");
});
var p2 = new Promise(function(resolve, reject) {
setTimeout(resolve, 1000, "two");
});
Promise.race([p1, p2]).then(result => {
console.log(result); // "two"
// 两个都resolved,但 p2 更快,故得到的resolved的promise采用p2 resolve的值
});
3. Promise.resolve(result)
返回一个给定resolve值的resolved状态的promise对象实例。
语法
Promise.resolve(value);
Promise.resolve(promise);
Promise.resolve(thenable);
param:
- 将被Promise对象resolve的值。可以是一个简单值,也可以是一个Promise对象实例,也可以是一个thenable
return:
- 如果参数是一个简单值,则返回一个resolved状态的带着resolved的值的Promise对象;
- 如果参数是一个promise对象,则直接返回这个Promise对象。
- 如果参数是一个thenable对象,则会跟随这个thenable对象,采用它最终状态的Promise
示例1:resolve简单值
Promise.resolve('success').then(result => {
console.log(result);//success
}, (err)=>{
console.log(err); //then的第二个参数这个函数不会被调用
});
示例2:resolve另一个promise对象
var promise1 = Promise.resolve('1');
var promise2 = Promise.resolve(promise1);
promise2.then(result => {
console.log(result);
});
console.log('promise1===promise2:', promise1===promise2);
/* 控制台输出(按顺序)
promise1===promise2: true
1
*/
示例3:resolve thenable对象
var thenableObj = {
then: (resolve,reject) => {
resolve('success');
}
}
console.log(Object.prototype.toString.call(thenableObj));//[object Object]
var promise1 = Promise.resolve(thenableObj);
console.log(promise1 instanceof Promise);//true
promise1.then((result) => {
console.log(result);//'success'
}, (err) => {
console.log(err);//不会调用
});
4. Promise.reject(err)
返回一个带有reject原因err的rejected状态的promise对象。
语法
Promise.reject(err)
param:
- err: 表示rejected的原因。可以为String或Err
return:
一个给定了reject原因的rejected状态的promise。
示例
Promise.reject(new Error("failed")).then(result => {
console.log(result);//then中的第一个函数未被调用
}, err => {
console.log(err);//Error:failed
});
四、Promise实例方法(原型方法)
1. Promise.prototype.then(onResolved, onRejected)
返回一个promise。最多需要两个参数:成功和失败情况的回调函数。
语法
promise.then(onResolved, onReject);
promise.then(result => {
//onResolved
}, err => {
//onRejected
});
Params:
- onResolved: 当promise变成resolved状态时,该参数作为回调函数被调用。该函数有一个参数,即resolve的结果。如果传入的onResolved参数不是函数类型,则会在内部被替换为(result)=>result,此result为then之前的promise resolve的值。
- onRejected: 当promise变成rejected状态时,该参数作为回调函数被调用。该函数有一个参数,即reject的错误原因。
Return:
then方法返回一个Promise,而它的行为与then中的回调函数的返回值有关:
- 如果then中的回调函数返回一个值,那么then返回的Promise将会成为resolved状态,并且将返回的值作为resolved回调函数的参数值。
- 如果then中的回调函数抛出一个错误,那么then返回的Promise将会成为rejected状态,并且将抛出的错误作为rejected回调函数的参数值。
- 如果then中的回调函数返回一个已经是resolved状态的Promise,那么then返回的Promise也会成为resolved状态,并且将那个Promise的resolved状态的回调函数的参数值作为该被返回的Promise的resolved状态回调函数的参数值。
- 如果then中的回调函数返回一个已经是rejected状态的Promise,那么then返回的Promise也会成为rejected状态,并且将那个Promise的rejected状态的回调函数的参数值作为该被返回的Promise的rejected状态回调函数的参数值。
- 如果then中的回调函数返回一个pending状态的Promise,那么then返回Promise的状态也是pending的,并且它的终态与那个Promise的终态相同;同时,它变为终态时调用的回调函数参数与那个Promise变为终态时的回调函数的参数是相同的。
示例1:传入then的参数不是函数
(new Promise((resolve, reject) => {
resolve('1')
})).then('2')
.then(result => {
console.log(result);//1
})
示例2:链式调用
Promise.resolve('1')
.then(result => {
return new Promise((resolve, reject)=>{
setTimeout(() => {
result += '2';
resolve(result);
}, 1000);
});
}).then(result => {
setTimeout(() => {
result += '3';
console.log(result);//123
//此处没有将新拼接的result resolve
}, 1000);
}).then(result => {
console.log(result);//undefined
});
示例3:链式调用中抛出错误
Promise.resolve()
.then(() => {
throw 'Oh no!';
})
.then(() => {
console.log('Not called');//没有被调用
}, err=>{
console.error('onRejected handler called:', err);//输出错误:onRejected handler called: Oh no!
});
示例4:链式调用中途得到rejected状态的promise
Promise.reject()
.then(
() => 1,//不执行
() => 2//执行
).then(result => {
console.log(result)//2
});
2. Promise.prototype.catch(onRejected)
返回一个promise,并且处理rejected状态。它的行为与调用Promise.prototype.then(undefined, onRejected) 相同。 (事实上, 调用catch(onRejected) 内部调用了then(undefined, onRejected)).
语法
promise.catch(onRejected);
promise.catch(err => {
})
Param:
- onRejected:当promise变为rejected状态时调用的处理函数。该函数拥有一个参数err,为获取的rejected的原因。
注意: 如果 onRejected处理函数抛出一个错误或返回一个本身就是rejected状态的 Promise ,那么通过该catch()返回的Promise会变为rejected状态;否则,它将回是resolved状态。
Return
一个promise
示例
var p1 = new Promise(function(resolve, reject) {
resolve('Success');
});
p1.then(function(value) {
console.log(value); // "Success"
throw 'oh, no!';
}).catch(function(e) {
console.log(e); // "oh, no!"
}).then(function(){
console.log('The promise returned by catch() is resolved'); //'The promise returned by catch() is resolved'
}, function () {
console.log('The promise returned by catch() is rejected');//没有执行
});
3. Promise.prototype.finally(onFinally)
返回一个promise。在执行then()和catch()后,都会执行finally(onFinally)中的onFinnally回调函数。它的意义是避免同样的语句需要在then()和catch()中各写一次的情况。
语法
promise.finally(onFinally);
promise.finally(() => {
})
Param:
- onFinnaly: Promise 状态改变后执行的回调函数。该函数无参数。
Return:
- 一个promise对象
注意:
- 由于无法知道promise的最终状态,所以finally的回调函数中不接收任何参数,它仅用于无论最终结果如何都要执行的情况。
- 与Promise.resolve(2).then(() => {}, () => {}) (resolved的结果为undefined)不同,Promise.resolve(2).finally(() => {}) resolved的结果为 2。
- 同样,Promise.reject(3).then(() => {}, () => {}) (resolved 的结果为undefined), Promise.reject(3).finally(() => {}) rejected 的结果为 3。
参考资料
http://exploringjs.com/es6/ch_promises.html
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Using_promises
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise/all
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise/resolve
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise/reject
理解Promise的更多相关文章
- 大白话讲解Promise(二)理解Promise规范
上一篇我们讲解了ES6中Promise的用法,但是知道了用法还远远不够,作为一名专业的前端工程师,还必须通晓原理.所以,为了补全我们关于Promise的知识树,有必要理解Promise/A+规范,理解 ...
- 彻底理解Promise对象——用es5语法实现一个自己的Promise(上篇)
本文同步自我的个人博客: http://mly-zju.github.io/ 众所周知javascript语言的一大特色就是异步,这既是它的优点,同时在某些情况下也带来了一些的问题.最大的问题之一,就 ...
- 理解Promise的三种姿势
译者按: 对于Promise,也许你会用了,却并不理解:也许你理解了,却只可意会不可言传.这篇博客将从3个简单的视角理解Promise,应该对你有所帮助. 原文: Three ways of unde ...
- 理解Promise的3种姿势
译者按: 对于Promise,也许你会用了,却并不理解:也许你理解了,却只可意会不可言传.这篇博客将从3个简单的视角理解Promise,应该对你有所帮助. 原文: Three ways of unde ...
- 分步理解 Promise 的实现
一个 Promise 的运用: var firstPromise = new Promise(function(resolve,reject){ setTimeout(function(){ var ...
- 理解promise 02
1:promise是什么? 就是(链式)包装的回调函数. 2:语法 new Promise( function(resolve, reject) {...} /* executor */ ); exe ...
- 160701、理解 Promise 的工作原理
Javascript 采用回调函数(callback)来处理异步编程.从同步编程到异步回调编程有一个适应的过程,但是如果出现多层回调嵌套,也就是我们常说的厄运的回调金字塔(Pyramid of Doo ...
- 160623、理解 Promise 的工作原理
Javascript 采用回调函数(callback)来处理异步编程.从同步编程到异步回调编程有一个适应的过程,但是如果出现多层回调嵌套,也就是我们常说的厄运的回调金字塔(Pyramid of Doo ...
- 理解Promise简单实现的背后原理
在写javascript时我们往往离不开异步操作,过去我们往往通过回调函数多层嵌套来解决后一个异步操作依赖前一个异步操作,然后为了解决回调地域的痛点,出现了一些解决方案比如事件订阅/发布的.事件监听的 ...
- 理解promise 01
原文地址: http://pouchdb.com/2015/05/18/we-have-a-problem-with-promises.html 用Javascript的小伙伴们,是时候承认了,关于 ...
随机推荐
- centos7 PXE自动安装环境搭建
原理: 要进行自动安装的主机A,加电启动时以网卡为第一启动设备 1.启动时会向网络广播,找到dhcp服务器B请求分配IP地址信息,服务器B除了给其分配基本的IP信息(ip.netmask.getewa ...
- 7.Django模型类的定义和管理
Django的模型类是给ORM层服务的 1.每个数据模型都是django.db.models.Model的子类. 2.它的父类Model包含了所有必要的和数据库交互的方法,并提供了定义数据库字段的语法 ...
- LATEX ——WinEdt 破解
WinEdt 是目前我发现最好的LaTeX编辑器,但是在国内支付不便,且学生许可需$40,只能出此下策,望有余力者尽量购买正版. WinEdt 的旧版本的破解方法众所周知,只需定时删除HKCU\Sof ...
- ALV调用的几个函数
转 ALV的调用主要由以下几个标准函数实现,所有函数的输入输出参数必须大写,否则系统会出现异常中止,相关函数如下: 1)REUSE_ALV_FIENDCATALOG_MERGE:根据内表结构返回FI ...
- Apache Shiro 使用手册(三)Shiro 授权(转发:http://kdboy.iteye.com/blog/1155450)
授权即访问控制,它将判断用户在应用程序中对资源是否拥有相应的访问权限. 如,判断一个用户有查看页面的权限,编辑数据的权限,拥有某一按钮的权限,以及是否拥有打印的权限等等. 一.授权的三要素 授权有着三 ...
- 关于align-items和align-content的区别和使用场景
最近在研究flex布局,容器中有两个属性,是用来定义crossAxis测轴排列方式的.一开始接触align-items还可以理解感觉不难,后来看到align-content就感觉有点混淆了,特开一篇博 ...
- input type="radio" jquery判断checked的三种方法:
<input type="radio" name="radioname" value="" />全部 <input typ ...
- 使用JavaScript定义一个微信小程序插件样例
var wxTimer = new wxTimer({ beginTime: "00:00:20", complete: function () { wx.redirectTo({ ...
- (转)Windows下面安装和配置MySQL(5.6.20)
原文地址:http://www.cnblogs.com/qiyebao/p/3887055.html 1.首先到http://dev.mysql.com/ 上下载windows版mysql5.6免安装 ...
- redis主从架构及redis集群
https://redis.io/topics/cluster-spec Redis Cluster does not support multiple databases like the stan ...