async 函數的實現原理,就是將 Generator 函數和自動執行器,包裝在一個函數裏。async 函數返回一個promise對象javascript
async function fn(args) { // ... } // 等同於 function fn(args) { return spawn(function* () { // ... }); }
全部的async
函數均可以寫成上面的第二種形式,其中的spawn
函數就是自動執行器。java
下面給出spawn
函數的實現,基本就是前文自動執行器的翻版。es6
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); }); }); }
場景:假設有兩個請求http://127.0.0.1:8888/getA
和http://127.0.0.1:8888/getB
,第二個請求依賴第一個請求結果。ajax
首先,封裝一個ajax請求json
// 使用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)) }) }
後端接口c#
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實現案例,須要咱們手動執行promise
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/awaitapp
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...async