版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
今天,我们创建自己的JavaScriptPromise实现[FromScratch]。要创建一个新的承诺,我们只需newPromise像这样使用:
newPromise((resolve,reject)=>{
...
resolve(someValue)
})我们传递一个定义Promise特定行为的回调。Promise是一个容器:为我们提供API来管理和转换价值这让我们能够管理和转变实际上尚不存在的价值。使用容器来包装值是函数式编程范例中的常见做法。函数式编程中有不同种类的“容器”。最著名的是函子和单子。实施承诺以了解其内部结构1、then()方法classPromise{
constructor(then)
{
this.then=then
}}constgetItems=newPromise((resolve,reject)=>{
HTTP.get('/items',(err,body)=>{
if(err)returnreject(err)
resolve(body)
})})getItems.then(renderItems,console.error)非常简单,到目前为止,这个实现除了具有success(
resolve)和error(
reject)回调的任何函数之外,没有做任何其他事情。因此,检查一下,当我们从头开始做出承诺时,我们有一个额外的(通常不公开的)步骤需要实施。2.映射目前,我们的Promise实现无法正常工作-它过于简化,并且不包含正常工作所需的所有行为。我们的实现目前缺少什么功能和/或行为之一?首先,我们无法链式.then()调用。Promise可以链接多个.then()方法,并且每次.then()解析其中任何语句的结果时都应返回一个新的Promise。这是让Promise如此强大的主要功能之一。它们帮助我们逃离回调地狱。这也是我们目前尚未实现的Promise实现的一部分。在我们的实现中,结合使Promise链正常工作所需的所有功能可能会有点混乱-但我们得到了这一点。让我们深入研究、简化并设置JavaScriptPromise的实现,以始终从语句返回或解析其他Promise
.then()。首先,我们需要一个方法来转换Promise包含的值并返回一个新的Promise。嗯,这听起来是不是很奇怪?让我们仔细看看。啊哈,这听起来和Atotype.map实现方式完全一样,不是吗?.map的类型签名是:map::(a->b)->Arraya->Arrayb简单来说,这意味着map接受一个函数并将type转换a为type
b。这可以是一个String到Boolean,然后它将采用a
(字符串)的数组并返回b
(布尔)的数组。我们可以构建一个Ptotype.map具有非常相似签名的函数,该函数Atotype.map允许我们将已解决的Promise结果映射到另一个正在进行的Promise。这就是我们能够链接.then's具有返回任何随机结果的回调函数的方式,但随后似乎神奇地以某种方式返回Promise,而无需我们实例化任何新的Promise。map::(a->b)->Promisea->Promiseb以下是我们如何在幕后实现这一魔法:classPromise{
constructor(then)
{
this.then=then
}
map(mapper)
{
returnnewPromise(
(resolve,reject)=>
this.then(x=>resolve(mapper(x)),
reject
)
)
}}我们刚才做了什么?让我们来分解一下。当我们创建或实例化Promise时,我们定义了一个回调,它是我们成功解析结果时使用的then回调。我们创建一个接受映射器函数的映射函数。这个映射函数返回一个新的承诺。在返回新的Promise之前,它会尝试解析先前Promise使用的结果。我们将map先前Promise的结果转换为新的Promise,然后回到在我们的map方法中实例化的新创建的Promise的范围内。.then我们可以继续这种模式,根据需要附加尽可能多的回调,并始终返回一个新的Promise,而无需在我们的map方法之外外部实例化任何新的Promise。(resolve,reject)=>this.then(...))正在发生的事情是我们this.then立即打电话。thethis指的是我们当前的Promise,因此this.then将为我们提供Promise当前的内部值,或者如果我们的Promise失败则给出当前的错误。我们现在需要给它一个resolve回调reject://nextresolve=x=>resolve(mapper(x))//nextreject=reject这是我们的地图功能中最重要的部分。首先,我们用mapper当前值填充我们的函数x:promise.map(x=>x+1)//Themapperisactuallyx=>x+1//sowhenwedomapper(10)//itreturns11.我们直接将这个新值(11在示例中)传递给resolve我们正在创建的新Promise的函数。如果Promise被拒绝,我们只需传递新的拒绝方法,而不对值进行任何修改。
map(mapper){
returnnewPromise((resolve,reject)=>this.then(
x=>resolve(mapper(x)),
reject
))
}constpromise=newPromise((resolve,reject)=>{
setTimeout(()=>resolve(10),1000)})promise
.map(x=>x+1)//=>Promise(11)
.then(x=>console.log(x),err=>console.error(err))//=>it'sgoingtolog'11'总而言之,我们在这里所做的事情非常简单。我们只是用映射器函数和下一个函数的组合resolve来覆盖我们的函数。
这会将我们的值传递给映射器并解析返回的值。resolvex多使用我们的Promise实现:constgetItems=newPromise((resolve,reject)=>{
HTTP.get('/items',(err,body)=>{
if(err)returnreject(err)
resolve(body)
})})getItems
.map(JSON.parse)
.map(json=>json.data)
.map(items=>items.filter(isEven))
.map(items=>items.sort(priceAsc))
.then(renderPrices,console.error)就像这样,我们就被束缚了。我们链接的每个回调都是一个有点死的简单函数。这就是为什么我们喜欢在函数式编程中进行柯里化。现在我们可以编写以下代码:getItems
.map(JSON.parse)
.map(prop('data'))
.map(filter(isEven))
.map(sort(priceAsc))
.then(renderPrices,console.error)可以说,鉴于您更熟悉函数语法,您可以说这段代码更干净。另一方面,如果您不熟悉函数语法,那么这段代码会变得非常混乱。因此,为了更好地理解我们正在做的事情,让我们明确定义我们的.then()方法在每次调用时将如何转换.map:步骤1:newPromise((resolve,reject)=>{
HTTP.get('/items',(err,body)=>{
if(err)returnreject(err)
resolve(body)
})})第2步:.then现在:then=(resolve,reject)=>{
HTTP.get('/items',(err,body)=>{
if(err)returnreject(err)
resolve(body)
})}
.map(JSON.parse).then就是现在:then=(resolve,reject)=>{
HTTP.get('/items',(err,body)=>{
if(err)returnreject(err)
resolve(JSON.parse(body))
})}步骤3:
.map(x=>x.data).then就是现在:then=(resolve,reject)=>{
HTTP.get('/items',(err,body)=>{
if(err)returnreject(err)
resolve(JSON.parse(body).data)
})}步骤4:
.map(items=>items.filter(isEven)).then就是现在:then=(resolve,reject)=>{
HTTP.get('/items',(err,body)=>{
if(err)returnreject(err)
resolve(JSON.parse(body).data.filter(isEven))
})}第6步:
.map(items=>items.sort(priceAsc)).then就是现在:then=(resolve,reject)=>{
HTTP.get('/items',(err,body)=>{
if(err)returnreject(err)
resolve(JSON.parse(body).data.filter(isEven).sort(priceAsc))
})}第6步:
.then(renderPrices,console.error).then叫做。我们执行的代码如下所示:HTTP.get('/items',(err,body)=>{
if(err)returnconsole.error(err)
renderMales(JSON.parse(body).data.filter(isEven).sort(priceAsc))})3.链接和flatMap()我们的Promise实现仍然缺少一些东西——链接。当您在方法内返回另一个Promise时.then,它会等待它解析并将解析的值传递给下一个.then内部函数。这个工作怎么样?在一个Promise中,.then也在压扁这个promise容器。数组类比为flatMap:[1,2,3,4,5].map(x=>[x,x+1])//=>[[1,2],[2,3],[3,4],[4,5],[5,6]][1,2,3,4,5].flatMap(x=>[x,x+1])//=>[1,2,2,3,3,4,4,5,5,6]getPerson.flatMap(person=>getFriends(person))//=>Promise(Promise([Person]))getPerson.flatMap(person=>getFriends(person))//=>Promise([Person])这是我们的签名细分,但如果很难理解,我建议您尝试多次追踪逻辑尾部,如果它没有点击,则尝试深入研究下面的直接实现。我们非常深入,并且没有函数式编程的经验,这种语法可能很难跟踪,但请尽力而为,让我们继续下面的内容。classPromise{
constructor(then)
{
this.then=then
}
map(mapper)
{
returnnewPromise(
(resolve,reject)=>this.then(
x=>resolve(mapper(x)),
reject
)
)
}
flatMap(mapper){
returnnewPromise(
(resolve,reject)=>this.then(
x=>mapper(x).then(resolve,reject),
reject
)
)
}}我们知道的flatMap映射器函数将返回一个Promise。当我们得到值x时,我们调用映射器,然后通过调用.then返回的Promise来转发我们的resolve和reject函数。getPerson
.map(JSON.parse)
.map(x=>x.data)
.flatMap(person=>getFriends(person))
.map(json=>json.data)
.map(friends=>friends.filter(isMale))
.map(friends=>friends.sort(ageAsc))
.then(renderMaleFriends,console.error)怎么样:)我们实际上通过分离Promise的不同行为来创建一个Monad。简单地说,monad是一个容器,它实现了具有以下类型签名的.map方法.flatMap:map::(a->b)->Monada->MonadbflatMap::(a->Monadb)->Monada->Monadb该flatMap方法也称为chain或bind。我们刚刚构建的实际上称为任务,方法.then通常命名为fork。classTask{
constructor(fork)
{
this.fork=fork
}
map(mapper)
{
returnnewTask((resolve,reject)=>this.fork(
x=>resolve(mapper(x)),
reject
))
}
chain(mapper)
{
returnnewTask((resolve,reject)=>this.fork(
x=>mapper(x).fork(resolve,reject),
reject
))
}}Task和Promise之间的主要区别在于
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 苗木培育工安全专项能力考核试卷含答案
- 售票值班员岗前客户服务考核试卷含答案
- 清扫工道德水平考核试卷含答案
- 干酪素点制工保密竞赛考核试卷含答案
- 2026年危重患者护理安全隐患课件
- 磁头研磨工岗前基础常识考核试卷含答案
- 电工发展趋势模拟考核试卷含答案
- 流行饰品制作工安全宣传考核试卷含答案
- 紧固件制造工安全演练测试考核试卷含答案
- 耳机与人耳配置测试工安全强化评优考核试卷含答案
- 2026年国有企业新员工转正综合评估及企业文化认同与岗位技能达标测试
- (2026版)《临床静脉导管维护操作专家共识》解读
- 2026年初中道德与法治教师资格证《学科知识与教学能力》真题分享
- 2026年实验室危化品管理规范
- 急诊ICU镇静镇痛管理
- 25-华为供应链管理(6版)
- 2025年临沂临港经济开发区公开招聘工作人员(5人)参考笔试试题及答案解析
- 集大轮机维护与修理讲义
- 初中语法每日小纸条
- GB/T 12459-2025钢制对焊管件类型与参数
- 2024秋九年级语文上册 第四单元 综合性学习 走进小说天地说课稿 新人教版
评论
0/150
提交评论