JavaScript异步之Promise
来源:互联网 发布:单片机智能反编译器 编辑:程序博客网 时间:2024/05/17 21:56
传统的JavaScript异步通常基于回调实现,但回调方式有两个重要的缺点:
不便于调试:由于回调函数是基于事件队列实现的,当回调方法条用时,其外部调用函数并不在函数执行栈中,这给debug带来了极大不便。来看下下面这个例子:
function init(name) { test(name)}setTimeout(function A() { setTimeout(function() { init(); }, 0);}, 0);
可以看到,setTimeout并未出现在异常堆栈中
- 回调地狱:在异步编程中,通常会出现回调嵌套的场景。一层层回调相互嵌套,称为回调地狱。严重影响代码可读性
Promise
由于传统回调的诸多缺点,Promise
被提出以一种更友好的方式解决上述问题。Promise
是什么呢?简单来说,Promise
是一个封装未来事件结果的可复用异步任务管理机制。从这个定义中,我们可以看到Promise
的几个主要特点:
- 异步:
Promise
是用于描述未来事件的,未来事件什么时候发生并不知晓,因而其必然是基于异步实现的 - 任务管理:当未来事件发生后,如何处理未来事件?未来事件成功如何处理?失败又如何处理?所以
Promise
还涉及到任务管理 - 可复用:一个未来事件可能有多个回调处理,同时异步任务也可能是多重嵌套的,即异步任务回调中还嵌套着另一个异步任务。所以
Promise
必须是可复用的
术语
首先来看下Promise
下几个常用术语:
- Promise:指一个拥有符合规范的then方法的对象
- thenable:指一个定义了then方法的对象
- resolve:改变一个promise对象从等待状态到已完成或拒绝状态,一旦改变,不可再改
- reject reason:拒绝原因
另外,一个Promise
中还有三个状态:
- pending:等待、初始状态
- fullfilled:已完成,未来事件操作成功
- rejected:已拒绝,未来事件操作失败
一个Promise
对象的状态变化只能有如下两种:
pending -----> fullfilled
或
pending ------> rejected
THEN
方法
Promise
所提供的,用于访问未来事件处理结果的方法:
Promise.then(onFulfilled, onRejected)/** - 两个参数均为可选,均有默认值,若不传入,则会使用默认值;* - 两个参数必须是函数,否则会被忽略,使用默认函数;* - onFulfilled: 在promise已完成后调用且仅调用一次该方法,该方法接受promise最终值作参数;* - onRejected: 在promise被拒绝后调用且仅调用一次该方法,该方法接受promise拒绝原因作参数;* - 两个函数都是异步事件的回调,符合JavaScript事件循环处理流程*/
Resolution
Promise
的核心就是一个resolution
的过程,即处理未来事件,并确定事件成功或失败的条件,并在对应条件下执行onFullfilled
或 onRejected
(由then方法传入)方法通知调用方。
接下来看一个Promise
的例子:
let myPromise = new Promise((resolve, reject) =>{ setTimeout(function(){ console.log('resolve'); resolve('success') }, 1000 * 3)});myPromise.then((msg) => { console.log("Yay!" + msg);});console.log("after execute promise");
对应的输出为:
after execute promiseresolveYay!success
从输出可以看出其异步特性:Promise
的实例化以及then
方法都不是阻塞式函数,javascript
依然继续向下执行,所以最先输出的便是after execute promise
。
(resolve, reject) =>{ setTimeout(function(){ console.log('resolve'); resolve('success') }, 1000 * 3)}
初始化Promise
对象时传入的处理函数是Promise
的核心,如上述代码所示,在该Promise
对象中设定一个3S的定时器。3S秒后,任务执行成功,所以通过调用resolve
将成功信息透出,同时resolve
方法又会通过onResolved
方法(即在then
方法中传入的处理函数)将该信息透出给调用者。至此,一个完整的Promise
流程执行完毕。其中resolve
reject
方法由Promise
提供,用户执行指定何时调用该方法即可。
接下来再来看一个例子:
let myPromise = new Promise((resolve, reject) =>{ setTimeout(function(){ console.log('resolve'); resolve('success') reject('failed') }, 1000 * 3)});myPromise.then((msg) => { console.log(msg) console.log("Yay!" + msg); return 'first promise'}, (reason) => { console.log('rejected:' + reason)});
对应的输出为:
resolvesuccessYay!success
可以看到,尽管同时调用了resolve
和reject
,但只有resolve
被执行了,这也再次验证了Promise
的状态不可变性:即Promise的状态一旦变为resolved
或rejected
便不会再改变。
接下来再改变下上述代码:
let myPromise = new Promise((resolve, reject) =>{ setTimeout(function(){ console.log('resolve'); resolve('success') resolve('success') }, 1000 * 3)});myPromise.then((msg) => { console.log(msg) console.log("Yay!" + msg); return 'first promise'}, (reason) => { console.log('rejected:' + reason)});
resolvesuccessYay!success
可以看到,尽管调用了两次resolve
方法,但onResolve
方法只执行了一次,即当promise
对象的状态一旦变为resolved
或是rejected
后,便不再执行resolve
或reject
方法。
看完了上述的例子,我们重新来看下resolve
和reject
方法:
Promise.resolve(x)/*resolve方法返回一个已决议的Promsie对象:若x是一个promise或thenable对象,则返回的promise对象状态同x;若x不是对象或函数,则返回的promise对象以该值为完成最终值;否则,详细过程依然按前文Promsies/A+规范中提到的规则进行。*/Promsie.reject(reason)/*返回一个使用传入的原因拒绝的Promise对象。*/
Promise.prototype.then
看完了resolve
方法和reject
方法,接下来来看下then
方法:
该方法为promsie添加完成或拒绝处理器,将返回一个新的promise,该新promise接受传入的处理器调用后的返回值进行决议;若promise未被处理,如传入的处理器不是函数,则新promise维持原来promise的状态。
来看下下面这个例子:
var promise = new Promise((resolve, reject) => { setTimeout(function() { resolve('success'); }, 10);});promise.then((msg) => { console.log('first messaeg: ' + msg);}).then((msg) => { console.log('second messaeg: ' + msg);});
其输出结果为:
first messaeg: successsecond messaeg: undefined
可以看到,第一个then
方法成功接收到了resolve
方法返回的结果,但第二个then
方法接收到的却是undefined
。这是为什么呢?then
方法会返回一个promise
对象,并且该新promise根据其传入的回调执行的返回值,进行决议,而函数未明确return
返回值时,默认返回的是undefined
,这也是上面实例第二个then
方法的回调接收undefined
参数的原因。
所以接下来我们队上次上述代码进行修改:
var promise = new Promise((resolve, reject) => { setTimeout(function() { resolve('success'); }, 10);});promise.then((msg) => { console.log('first messaeg: ' + msg); return 'succss';}).then((msg) => { console.log('second messaeg: ' + msg);});
对应的输出就变为:
first messaeg: successsecond messaeg: success
Promise.prototype.catch
catch
方法等同于then
方法中的onRejected
方法,为promise对象添加异常处理逻辑。
链式调用
正式由于then
方法返回一个promise对象,所以可以基于Promise实现链式回调调用:
var fourthPromise = new Promise((resolve, reject) => { setTimeout(()=>{ console.log('first promise') resolve('first success'); },1000);}).then((msg) => { console.log(msg) return new Promise((resolve, reject) => { console.log('second promise') setTimeout(() => {resolve('second success')}, 1000) })}).then((msg) => { console.log(msg) return new Promise((resolve, reject) => { console.log('third promise') setTimeout(() => {resolve('third success')}, 1000) })});fourthPromise.then((msg) => { console.log(msg)})
对应的输出为:
first promisefirst successsecond promisesecond successthird promisethird success
- JavaScript异步之Promise
- 【windows8开发】异步编程之Promise(Javascript)
- 【windows8开发】异步编程之Promise(Javascript)
- Javascript中异步编程之Promise
- 异步JavaScript与Promise
- 异步编程之Promise
- Javascript异步流程控制之Promise(1)-Angular $q简介
- javascript之Promise:异步请求代码与结果处理分离
- Javascript异步流程控制之Promise(3)-ES6原生Promise简介
- JavaScript异步编程-Promise模式
- javascript异步下载 Promise实现
- 谈谈JavaScript异步操作Promise
- JavaScript基础之Promise
- JavaScript之Promise实现
- Javascript_异步编程之Promise
- js异步之promise(ES6)
- ES6--异步操作之Promise
- JavaScript异步编程的Promise模式
- 懒人得多动脑 HNUST 1884
- HDOJ 2011 多项式求和
- C++,OpenCV 中template(模板)的简单理解
- HDU2700-Parity
- 数据结构——二叉树的递归与非递归遍历(先序,中序,后序)
- JavaScript异步之Promise
- 从作用机制和性质上看待methods,watch和computed的关系
- C#窗体绘制基本理解
- 安师大是的是的
- Java--jvm
- JsonUtility解析Json
- CodeForces
- 内排序- 当有两种以上变元的时候的贪心算法
- Gym