You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
letPromise=require('./3.1.promise.js')letp=newPromise((resolve,reject)=>{resolve('xx')})p.then((data)=>{console.log('p success',data)},(err)=>{console.log(err)})// => p success xx
letPromise=require('./3.1.promise.js')letp2=newPromise((resolve,reject)=>{setTimeout(()=>{resolve('xxx')},1000)})p2.then((data)=>{console.log('p2 success',data)},(err)=>{console.log(err)})// => p success xx// p second success xx
letPromise=require('./3.2.promise.js')letp=newPromise((resolve,reject)=>{setTimeout(()=>{resolve('xxx')},1000)})p.then((data)=>{console.log('p success',data)},(err)=>{console.log(err)})p.then((data)=>{console.log('p second success',data)},(err)=>{console.log(err)})// 一秒以后打印// => p success xxx// p second success xxx
letPromise=require('./3.6.promise.js')// catchletp=newPromise((resolve,reject)=>{setTimeout(()=>{resolve('xxx')},1000)})p.then((data)=>{console.log(`p success then ${data}`)}).then((data)=>{thrownewError('just happy')}).catch(err=>{console.log(`p ${err}`)})// => p success then xxx// p Error: just happy
function*say(){leta=yield'hello'console.log('a',a)letb=yield'careteen'console.log('b',b)letc=yield'lanlan'console.log(c)}letit=say()it.next(100)// 第一次next传递参数 是无意义的it.next(200)it.next(300)// => a 200// b 300
异步发展流程-手摸手带你实现一个promise
篇幅较长,但重点为以下几点,可直接前往感兴趣的话题,各取所需。
所有涉及的例子均有完整代码存放在仓库,感兴趣的同学可直接clone在本地运行。
本文主要简单探讨下异步的前世今生,并手摸手带你实现一个promise
由于JavaScript单线程的特性,我们需要异步编程解决阻塞问题。
异步编程问题
我们每天的工作中都可能会用到以下函数做一些异步操作
如何解决异步问题
解决异步问题现有的方式如下
下面将逐一介绍各种方式如何解决异步问题
回调函数
首先介绍一下高阶函数,即一个函数的参数是函数或者函数返回值为函数,此函数称做高阶函数。
lodash-after函数
再来看一个例子,常使用lodash的同学应该熟悉的一个方法_.after(n, fn),作用是fn函数在调用n次以后才会执行。
那如何实现一个
after
函数呢,其实主要是利用闭包和计数的思想:其中
cb
作为函数参数传入after
函数,即是高阶函数的一个应用。after函数例子地址
⬆️回到顶部
Node读取文件
现在有一个场景,读取两个文件内容,赋值给一个对象,并打印。
在./static下新建了两个文件
name.txt
,age.txt
,期望读取文件内容并赋值给一个对象,然后打印。由于读取文件的过程是异步的,所以通过这种方式是无法满足预期的。
并且异步操作存在以下三个问题
回调地狱大家应该非常熟悉了。
本例地址
并且两个文件读取时间是累加,不是并行的,如果文件很多并且很大,那等待时间将非常久,所以并不推荐。
这里针对第三个问题多个异步操作,在同一时间内,如何同步异步的结果?,可以采用发布订阅的方式解决
不了解发布订阅模式的请移步我的另一篇博客
通过以下操作即可达到预期
在每次读取文件时触发打印事件,事件中进行判断只有两次读取都完成的情况下才会打印。
以上方法看似解决了上面提到的第三个问题多个异步操作,在同一时间内,同步异步的结果,但是随着需求的变动,需要再读取一个
address
文件,就需作如下变动:再新增多项的话,代码的扩展性就非常差了。
下面将将介绍如何实现一个promise然后解决上面提到的问题
node读取文件代码地址
⬆️回到顶部
为什么要用promise
那么接下来介绍promise的出现所解决的问题
promise用法
手摸手带你撸一个promise
首先需要提到promise/A+规范,我们自己编写的promise是需要一个标准的。可以根据此标准一步一步来。
需要三个状态
pending
时fulfilled
或rejected
fulfilled
或rejected
时value
或reason
且不能改变⬆️回到顶部
then方法
更详细请移步文档,这里说几个重点
executor
函数中代码异常的情况executor
函数中代码为异步的情况处理
executor
函数中代码异常的情况对
executor
try-catch即可如下使用
简易版1.0.0地址以及测试用例地址
虽然实现了一个很简易的promise,但还存在很多问题,比如下面
对于异步的代码是不会处理的
⬆️回到顶部
处理
executor
函数中代码为异步的情况使用发布订阅模式的思想处理
使用
简易版1.0.1地址以及测试用例地址
⬆️回到顶部
处理then的链式调用
和
jQuery
的链式调用一个套路,不过在这儿需要返回一个新的promise
而不是当前,因为成功态和失败态是不能转为其他状态的使用
简易版1.0.2地址以及测试用例地址
如代码中只是简单处理
_resolvePromise
方法⬆️回到顶部
完善_resolvePromise
再移步规范文档处理_resolvePromise
需要考虑以下几种情况
_resolvePromise (promise2, x, resolve, reject)
考虑以上进行完善
使用
简易版1.0.3地址以及测试用例地址
⬆️回到顶部
以上一个符合
Promise/A+
规范的promise基本完成那怎么验证自己写的promise是否正确呢?
追加以下
deferred
方法以供检查安装检查工具
promises-aplus-tests
执行检查
都是绿色表示检查通过
代码地址
⬆️回到顶部
promise周边
以上只是一个简易的promise,我们期望完善更多功能:
下面实现的地址在简易版1.1.1以及测试用例
catch方法
实现
使用
⬆️回到顶部
静态方法
实现
使用
⬆️回到顶部
finally方法
实现
使用
⬆️回到顶部
all方法
实现
使用
⬆️回到顶部
race方法
实现
使用
⬆️回到顶部
generator用法
在理解generator之前先看一个例子。
实现一个可传任意个参数的加法函数
老司机们三下五除二就能得出求和函数
以上代码地址
使用ES6的展开运算符
...
可枚举出所有参数,再用数组包裹,即可将一个类数组转换为一个数组。利用reduce实现累加,方可得出求和函数。那展开运算符能否操作对象佯装的类数组呢?那就来试一试
以上代码地址
可得知对象是不能被迭代的,根据报错信息,我们再改进代码
再使用generator实现
以上代码地址
生成器可以实现生成迭代器,生成器函数就是在函数关键字中加个*再配合yield来使用,并且yield是有暂停功能的。
那如何遍历迭代器呢?
以上代码地址
迭代器提供
next
方法,可得出迭代的value
和是否已经迭代完成done
,用一个循环即可遍历。yield的返回值的使用场景
以上代码地址
generator执行流程大体如下图
可看出第一次next传递参数是无意义的,所以输出结果为
a 200 b 300
以上均为同步的情况,接下来看下yield后面是异步的场景。
再通过一个例子来深入理解。
通过读取文件
1.txt
的内容为2.txt
,再读取2.txt
的内容为3.txt
,最后读取3.txt
中的内容Careteen
首先需要准备三个文件,放置在
./static
目录下,再准备读取文件的函数,在使用generator实现读取函数
期望的过程是通过读取文件
1.txt
的内容为2.txt
,再读取2.txt
的内容为3.txt
,最后读取3.txt
中的内容Careteen
,进行返回。首先我们能想到使用回调的方式解决,因为yield后面是一个promise
但这又会产生回调地狱,所以需要优化,我们需要一个迭代函数,通过递归可以实现
使得异步可以按顺序来执行,最后看一下执行
以上代码地址
非常完美的实现了,但是如果yield的后面是一个同步操作,没有then方法,在
co
方法中我们还需要特殊处理,也比较简单。牛逼的TJ大神的CO库就对此做了很完善的处理,感兴趣的可前往仓库看看源码,只有200多行。
generator的应用:
如何实现generator
可查看babel编译后的结果
⬆️回到顶部
async-await
写起来是同步的,语法糖很甜不腻。
bluebird
async-await
async-await内部机制
例子
通过babel编译后可看出实质上是通过
generator+co
的方式实现的。⬆️回到顶部
The text was updated successfully, but these errors were encountered: