async 的原理
admin
2024-03-25 18:47:51
0

ES2017 标准引入了 async 函数,使得异步操作变得更加方便。

async 函数是什么?一句话,它就是 Generator 函数的语法糖。研究 async 的原理,就必须先弄清楚 Generator 是个啥。

Generator 函数是 ES6 提供的一种异步编程解决方案,语法行为与传统函数完全不同。

形式上,Generator 函数是一个普通函数,但是有两个特征。一是,function关键字与函数名之间有一个星号;二是,函数体内部使用yield表达式,定义不同的内部状态(yield在英语里的意思就是“产出”)

看一个例子:

function* gen(x) {var y = yield x + 2;return y;
}var g = gen(1);
g.next() // { value: 3, done: false }
g.next() // { value: undefined, done: true }

上面代码中,调用 Generator 函数,会返回一个内部指针(即遍历器)g。这是 Generator 函数不同于普通函数的另一个地方,即执行它不会返回结果,返回的是指针对象。调用指针gnext方法,会移动内部指针(即执行异步任务的第一段),指向第一个遇到的yield语句,上例是执行到x + 2为止。

换言之,next方法的作用是分阶段执行Generator函数。每次调用next方法,会返回一个对象,表示当前阶段的信息(value属性和done属性)。value属性是yield语句后面表达式的值,表示当前阶段的值;done属性是一个布尔值,表示 Generator 函数是否执行完毕,即是否还有下一个阶段。

这样手工的执行next()函数,着实有些麻烦,能写个工具让他自动执行吗?那我们就来试试:

封装一个 spawn 函数,返回一个 spawn 函数,给函数传入 Generator 函数作为参数,spawn 实现 next() 方法的执行。

function fn(args) {return spawn(function* () {// ...});
}

spawn 函数的实现:

function spawn(genF) {return new Promise(function(resolve, reject) {const gen = genF();function step(nextF) {let next;try {next = nextF();} catch(e) {return reject(e);}if(next.done) {return resolve(next.value);}Promise.resolve(next.value).then(function(v) {step(function() { return gen.next(v); });}, function(e) {step(function() { return gen.throw(e); });});}step(function() { return gen.next(undefined); });});
}

应用这个方法执行一下第一个例子:

function fn(x) {return spawn(function* gen() {var y = yield x + 2return y;});
}fn(1).then((result) => {console.log(result) // 3
})

如果 yield 后面是个 Promise, 就可以实现异步了:

function fn(x) {return spawn(function* gen() {var y = yield new Promise((resolve) => {setTimeout(() => {resolve(x + 1)}, 1000)})return y;});
}fn(1).then((result) => {console.log(result) // 过一秒后打印 3
})

这样,过一秒后就打印 3 了。

从整个代码上来看,实现起来有些麻烦。Async 简化了一切,使用它,不再需要 spawn 函数,只需将 Generator 函数的星号(*)替换成async,将yield替换成await,仅此而已。改造一下:

async function fn(x) {let result = await new Promise((resolve) => {setTimeout(() => {resolve(x + 2)}, 1000)})return result
}fn(1).then((result) => {console.log(result)
})

真是简洁了很多。

最后看一个面试题,如何将程序的执行结果 1,3,2,改造为 1,2, 3


只需修改一个 onGetUser 函数即可:

async onGetUser() {// getUser().then((result) => {//   console.log(result)// })let result = await getUser()console.log(result)
}

相关内容

热门资讯

市场监管总局:开展制止滥用行政... 5月6日消息,市场监管总局4月30日召开党组(扩大)会议,传达学习4月28日中央政治局会议精神,研究...
澳大利亚将建造国有燃油储备 5月6日消息,澳大利亚总理阿尔巴尼斯宣布,该国将投入超过100亿澳元(1澳元约合4.9元人民币)增加...
国内期货主力合约收盘涨多跌少 5月6日消息,国内期货主力合约收盘涨多跌少,沪锡涨超8%,碳酸锂涨超7%,沪银、集运欧线涨超5%,烧...
外资净买入价值3.13万亿韩元... 5月6日消息,外资净买入价值3.13万亿韩元的韩国综合股价指数(KOSPI)成分股,创下该市场有史以...
美光科技:245TB容量的美光... 5月6日消息,美光科技近日宣布,正式出货245TB容量的美光6600 ION SSD。美光245TB...
港股黄金股午后震荡走高,山东黄... 5月6日消息,港股黄金股午后震荡走高,山东黄金、灵宝黄金涨超5%,洛阳钼业涨超3%,周大福、紫金矿业...
AMD苏姿丰:预计第二季度服务... 5月6日消息,AMD(超威半导体)董事会主席兼首席执行官苏姿丰在2026年第一季度财报电话会上表示,...
电池产业链震荡拉升,宁德时代涨... 5月6日消息,电池产业链震荡拉升,容百科技涨超10%,丰元股份此前涨停,宁德时代涨近7%续创历史新高...
隆华新材:目前暂未知悉下游厂商... 5月6日消息,隆华新材在互动平台表示,结合公司产品的特性,公司密切关注和探索新兴领域的应用,目前暂未...
戴姆勒卡车公司营业利润减半,需... 5月6日消息,全球最大卡车制造商之一戴姆勒卡车公司周三表示,受历史性疲软的需求及其关键市场北美地区进...