async/await原理實現

一、async 函數的實現原理

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/getAhttp://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

相關文章
相關標籤/搜索