再谈Promise以及其实现-没有基于Promise/A规范
栏目: JavaScript · 发布时间: 6年前
内容简介:在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负责人:没有中国的认可,开源标准没有意义
- 建模的世界没有银弹
- 私有链可能没有未来?
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
The Mechanics of Web Handling
David R. Roisum
This unique book covers many aspects of web handling for manufacturing, converting, and printing. The book is applicable to any web including paper, film, foil, nonwovens, and textiles. The Mech......一起来看看 《The Mechanics of Web Handling》 这本书的介绍吧!