1、async 函数的实现原理
async 函数的实现原理,就是将 Generator 函数和自动执行器,包装在一个函数里。async 函数返回一个promise对象
async function fn(args) {
// ...
}
// 等同于
function fn(args) {
return spawn(function* () {
// ...
});
}
所有的async
函数都可以写成上面的第二种形式,其中的spawn
函数就是自动执行器。
下面给出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); // 需要return,不然无法终结递归
}
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); });
});
}
2、案例
场景:假设有两个请求http://127.0.0.1:8888/getA
和http://127.0.0.1:8888/getB
,第二个请求依赖第一个请求结果。
首先,封装一个ajax请求
// 使用ajax封装post请求
function post (url, params) {
return new Promise((reslove, reject) => {
let xhr = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject()
xhr.onreadystatechange = () => {
if (xhr.readyState === 4 && xhr.status === 200) {
// coding
reslove(xhr.response)
}
}
xhr.open('POST', url, true)
// Failed to execute 'setRequestHeader' on 'XMLHttpRequest': The object's state must be OPENED.
// 设置请求头,请求头的设置必须在xhr打开之后,并且在send之前
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
xhr.setRequestHeader('Accept', 'application/json')
xhr.send(JSON.stringify(params))
})
}
后端接口
const http = require('http')
// const querystring = require('querystring')
// 创建服务
http.createServer((request, response) => {
response.writeHead(200, {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET, POST, DELETE, PUT, OPTIONS, HEAD",
"Access-Control-Allow-Headers": "User-Agent, Origin, Cache-Control, Content-Type",
"Content-Type": "application/json",
})
if (request.method === 'OPTIONS') {
response.end()
}
if (request.url === '/getA' && request.method === 'POST') {
let allData = ''
request.on('data', chunk => {
allData += chunk
})
request.on('end', () => {
allData = JSON.parse(allData)
response.end(JSON.stringify(allData))
})
}
if (request.url === '/getB' && request.method === 'POST') {
let allData = ''
request.on('data', chunk => {
allData += chunk
})
request.on('end', () => {
allData = JSON.parse(allData)
response.end(JSON.stringify(allData))
})
}
}).listen(8888)
console.log('serve is loading~~~')
使用async/await实现案例
async function handler () {
let data1 = await post('http://127.0.0.1:8888/getA', {name: '张三'})
return await post('http://127.0.0.1:8888/getB', Object.assign({age: 20}, JSON.parse(data1)))
}
handler().then(res => {console.log(res)}) // {age: 20, name: '张三'}
使用generator实现案例,需要我们手动执行
function* handler () {
// yield 后边表达式返回的是一个promise对象
let data1 = yield post('http://127.0.0.1:8888/getA', {name: '张三'}) // 使用next参数,不然data1 === undefined
let data2 = yield post('http://127.0.0.1:8888/getB', Object.assign({'age': 20}, JSON.parse(data1)))
return data2
}
var gen = handler()
// `yield`表达式本身没有返回值,或者说总是返回`undefined`。`next`方法可以带一个参数,该参数就会被当作上一个`yield`表达式的返回值。
// gen.next() 为 {value: Promise, done: false}
// gen.next(v) 为 {value: Promise, done: false}
// gen.next(r) 为{value: {age: 20, name: '张三'}, done: true}
gen.next().value.then(v => {gen.next(v).value.then(r => {console.log(gen.next(r).value)})})
我加上一个自执行函数就可以让generator等价于async/await
function fn() {
return spawn(handler) // 返回promise对象
}
fn().then(res => {console.log(res)}) // {age: 20, name: '张三'}
参考:
https://juejin.im/post/5bb22f...
https://juejin.im/post/5da5dc...
https://es6.ruanyifeng.com/#d...
https://juejin.im/post/5e79e8...
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。