再谈Promise以及其实现-没有基于Promise/A规范
栏目: JavaScript · 发布时间: 5年前
内容简介:在js中,异步是一个非常重要的组成部分,它基于事件循环,保证了优先级更高任务的优先执行权,比如js下载、UI渲染、js中非异步的任务,异步使得单进程的js能够做到非阻塞,这在node显得攸关重要,它使得js不必等待I/O操作返回结果,而能去处理其他任务。但是异步也存在着缺点,最明显的就是回地狱,而Pormise规范的出现,让开发者从回调地狱从解放出来。它由社区提出和实现,之后被es6加入到标准当中。Promise最基本的是由status、resolve、onResolved、reject、onRejecte
在js中,异步是一个非常重要的组成部分,它基于事件循环,保证了优先级更高任务的优先执行权,比如js下载、UI渲染、js中非异步的任务,异步使得单进程的js能够做到非阻塞,这在node显得攸关重要,它使得js不必等待I/O操作返回结果,而能去处理其他任务。但是异步也存在着缺点,最明显的就是回地狱,而Pormise规范的出现,让开发者从回调地狱从解放出来。它由社区提出和实现,之后被es6加入到标准当中。
Promise的组成
Promise最基本的是由status、resolve、onResolved、reject、onRejected、then和catch几部分组成:
status:状态管理,有pendding,fulfilled和rejected三种状态,且状态一经改变是无法逆转的;
resolve: 一个函数,当调用该函数时,说明异步任务执行成功了,promise的status由pendding转为fulfilled,且会调用成功的回调函数onResolved;
reject: 一个函数,当调用该函数时,说明异步任务执行失败,promise的status由pendding转为rejected,且会调用失败的回调函数onRejected;
then: 一个函数,在then的参数里面,我们需要定义回调成功需要执行的成功回调函数,promise会将这个成功回调函数注册到onResolved,由resolve触发调用,并且还支持链式调用;
catch: 一个函数,在reject的参数里面,我们需要回调失败需要执行的失败回调函数,promise会将这个失败回调函数注册到onRejected,由reject触发调用;
备注: 这里没讲race和all方法等,有兴趣的可以去看下文档。
使用方法
通过new创建一个Promise对象,传入一个函数参数,这个函数包含resolve和reject参数,这两个参数,如上所述也是函数,当异步任务完成的时候,调用resolve方法,当异步任务失败的时候,调用reject方法。eg:
var p = new Promise(function(resolve, reject){ setTimeout(function() { resolve(1) }, 1000) }) 复制代码
then
方法,参数也是一个回调函数,当你调用resolve方法后,这个回调函数就会调用,且resolve函数传入的参数,会带给这个回调函数的参数,eg:
p.then(function(arg){ console.log(arg) // 1 }) 复制代码
catch
方法,参数同样是一个回调函数,当你调用reject方法后,这个回调函数就会调用,且reject函数传入的参数,会带给这个回调函数,使用例子和then同理。
所以我们的Promise的调用可以是这样的:
var p = new Promise(function(resolve, reject){ // 异步任务执行,且看结果调用resolve还是reject }).then(function(){ // do something1 return new Promise... }).then(function() { // do something2 return new Promise.... }).then(function() { // do something3 return new Promise.... }).then(function() { // do something4 return new Promise.... }) 复制代码
对比用回调的方式
doAsyncTask1(function(){ // do something1 doAsyncTask2(function() { // do something2 doAsyncTask3(function() { // do something3 doAsyncTask4(function(){ // do something4 }) }) }) }) 复制代码
是不是比起异步编程,promise更人性化呢?
async await
上面promise的调用方式其实还不够优雅,还有更加优雅的调用方式,那就是async await方式,我们来看下如何用。
async testPromise() { var result = await new Promise(function(resolve, reject){ setTimeout(function(){ resolve(1) }, 2000) }) console.log(result) var result1 = await new Promise(function(resolve, reject){ setTimeout(function(){ resolve(1) }, 2000) }) console.log(result1) } 复制代码
是不是已经变成了我们同步的编程方式了?
这里有两点需要注意的:
- await关键字必须在使用async修饰的方法中才能使用,反之则没问题。
- async不能直接使用,需要使用babel进行转译,一般需要借助webpack进行配置,不能单独在js中使用,这个相对来说比较麻烦。
如何实现自己实现Promise
面试官很喜欢问你如何实现一个Promise,这个时候我们就需要对Promise有一定的理解,我们不去看Promise/A+规范,太复杂晦涩难懂了,我们就按照上面讲的Promise的组成来实现一个简单的Promise。
function _Promise(fn) { this.status = 'pending'; this.onResolved = null; this.onRejected = null; fn.call(this, this.resolve.bind(this), this.reject.bind(this)) } _Promise.prototype.resolve = function(arg) { if(this.status === 'pending') { this.onResolved(arg) this.status = 'fulfilled' } } _Promise.prototype.reject = function(arg) { if(this.status === 'pending') { this.onRejected(arg) this.status = 'rejected' } } _Promise.prototype.then = function(onResolved) { this.onResolved = onResolved } _Promise.prototype.reject = function(onRejected) { this.onResolved = onRejected } 复制代码
这就是一个最简单的Promise实现方式,但是它还不支持链式调用。所以我们需要在then方法再返回一个Promise, 我们改造一下:
function _Promise(fn) { this.status = 'pending'; this.onResolved = null; this.onRejected = null; this.childReject = null; this.childResolve = null; fn.call(this, this.resolve.bind(this), this.reject.bind(this)) } _Promise.prototype.resolve = function(arg) { if(this.status === 'pending') { if(this.onResolved) { var ret = this.onResolved(arg) // 如果第二个then return的是一个用户自定义的promise,我们称为PromiseB,则需要把childResolve赋值给这个PromiseB的onResolved,交给这个PromiseB来执行 if(ret instanceof _Promise) { ret.onResolved = this.childResolve return } // 否则直接调用childResove确保第二个then的回调执行 this.childResolve && this.childResolve() } this.status = 'fulfilled' } } _Promise.prototype.reject = function(arg) { if(this.status === 'pending') { this.onRejected && this.onRejected(arg) this.childReject && this.childReject() this.status = 'rejected' } } _Promise.prototype.then = function(onResolved) { this.onResolved = onResolved var that = this // 定义一个promise,我们简称PromiseA,以便链式调用 return new _Promise(function(resolve, reject){ // 这里需要确保resolve方法在第一个promise的resolve调用后调用,那么需要把它保存到第一个promise里面 that.childResolve = resolve that.childReject = reject }) } _Promise.prototype.reject = function(onRejected) { this.onResolved = onRejected } // 例子 new _Promise((resolve) => { setTimeout(() => { resolve() }, 2000) }).then(() => { console.log('promise success') return new _promise((resolve) => { setTimeout(() => { resolve() }, 1000) }) }).then(() => { console.log('promise2 success') }) 复制代码
这个实现,有三个Promise,第一个是首个Promise,第二个PormiseA即使如果then方法没有返回用户自定义的Promise的时候,我们方便链式调用的Promise,第三个PromiseB是then方法返回用户自定义的Promise的时候,我们需要把第二个then的回调交还给PromiseB执行。
以上所述就是小编给大家介绍的《再谈Promise以及其实现-没有基于Promise/A规范》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- 使用Datomic实现没有麻烦的事件溯源
- 卢森堡大学教授:如何实现没有第三方的公平交换?
- 0615 - 没有比较,就没有伤害
- 对话微软ONNX负责人:没有中国的认可,开源标准没有意义
- 建模的世界没有银弹
- 私有链可能没有未来?
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Java Web高级编程
威廉斯 (Nicholas S.Williams) / 王肖锋 / 清华大学出版社 / 2015-6-1 / CNY 99.80
Java成为世界上编程语言之一是有其优势的。熟悉JavaSE的程序员可以轻松地进入到Java EE开发中,构建出安全、可靠和具有扩展性的企业级应用程序。编写《Java Web高级编程——涵盖WebSockets、Spring Framework、JPA Hibernate和 Spring Security》一书的目的正是如此。 《Java Web高级编程:涵盖WebSockets、Sp......一起来看看 《Java Web高级编程》 这本书的介绍吧!