摘要:大約后輸出我們直接在官網的粘貼上述代碼,然后查看代碼編譯成什么樣子相關的代碼我們在系列之將編譯成了什么樣子中已經介紹過了,這次我們重點來看看函數以上這段代碼主要是用來實現的自動執行以及返回。
前言
本文就是簡單介紹下 Async 語法編譯后的代碼。
Asyncconst fetchData = (data) => new Promise((resolve) => setTimeout(resolve, 1000, data + 1)) const fetchValue = async function () { var value1 = await fetchData(1); var value2 = await fetchData(value1); var value3 = await fetchData(value2); console.log(value3) }; fetchValue(); // 大約 3s 后輸出 4Babel
我們直接在 Babel 官網的 Try it out 粘貼上述代碼,然后查看代碼編譯成什么樣子:
"use strict"; function _asyncToGenerator(fn) { return function() { var gen = fn.apply(this, arguments); return new Promise(function(resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then( function(value) { step("next", value); }, function(err) { step("throw", err); } ); } } return step("next"); }); }; } var fetchData = function fetchData(data) { return new Promise(function(resolve) { return setTimeout(resolve, 1000, data + 1); }); }; var fetchValue = (function() { var _ref = _asyncToGenerator( /*#__PURE__*/ regeneratorRuntime.mark(function _callee() { var value1, value2, value3; return regeneratorRuntime.wrap( function _callee$(_context) { while (1) { switch ((_context.prev = _context.next)) { case 0: _context.next = 2; return fetchData(1); case 2: value1 = _context.sent; _context.next = 5; return fetchData(value1); case 5: value2 = _context.sent; _context.next = 8; return fetchData(value2); case 8: value3 = _context.sent; console.log(value3); case 10: case "end": return _context.stop(); } } }, _callee, this ); }) ); return function fetchValue() { return _ref.apply(this, arguments); }; })(); fetchValue();_asyncToGenerator
regeneratorRuntime 相關的代碼我們在 《ES6 系列之 Babel 將 Generator 編譯成了什么樣子》 中已經介紹過了,這次我們重點來看看 _asyncToGenerator 函數:
function _asyncToGenerator(fn) { return function() { var gen = fn.apply(this, arguments); return new Promise(function(resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then( function(value) { step("next", value); }, function(err) { step("throw", err); } ); } } return step("next"); }); }; }
以上這段代碼主要是用來實現 generator 的自動執行以及返回 Promise。
當我們執行 fetchValue() 的時候,執行的其實就是 _asyncToGenerator 返回的這個匿名函數,在匿名函數中,我們執行了
var gen = fn.apply(this, arguments);
這一步就相當于執行 Generator 函數,舉個例子:
function* helloWorldGenerator() { yield "hello"; yield "world"; return "ending"; } var hw = helloWorldGenerator();
var gen = fn.apply(this, arguments) 就相當于 var hw = helloWorldGenerator();,返回的 gen 是一個具有 next()、throw()、return() 方法的對象。
然后我們返回了一個 Promise 對象,在 Promise 中,我們執行了 step("next"),step 函數中會執行:
try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; }
step("next") 就相當于 var info = gen.next(),返回的 info 對象是一個具有 value 和 done 屬性的對象:
{value: Promise, done: false}
接下來又會執行:
if (info.done) { resolve(value); } else { return Promise.resolve(value).then( function(value) { step("next", value); }, function(err) { step("throw", err); } ); }
value 此時是一個 Promise,Promise.resolve(value) 依然會返回這個 Promise,我們給這個 Promise 添加了一個 then 函數,用于在 Promise 有結果時執行,有結果時又會執行 step("next", value),從而使得 Generator 繼續執行,直到 info.done 為 true,才會 resolve(value)。
不完整但可用的代碼(function() { var ContinueSentinel = {}; var mark = function(genFun) { var generator = Object.create({ next: function(arg) { return this._invoke("next", arg); } }); genFun.prototype = generator; return genFun; }; function wrap(innerFn, outerFn, self) { var generator = Object.create(outerFn.prototype); var context = { done: false, method: "next", next: 0, prev: 0, sent: undefined, abrupt: function(type, arg) { var record = {}; record.type = type; record.arg = arg; return this.complete(record); }, complete: function(record, afterLoc) { if (record.type === "return") { this.rval = this.arg = record.arg; this.method = "return"; this.next = "end"; } return ContinueSentinel; }, stop: function() { this.done = true; return this.rval; } }; generator._invoke = makeInvokeMethod(innerFn, context); return generator; } function makeInvokeMethod(innerFn, context) { var state = "start"; return function invoke(method, arg) { if (state === "completed") { return { value: undefined, done: true }; } context.method = method; context.arg = arg; while (true) { state = "executing"; if (context.method === "next") { context.sent = context._sent = context.arg; } var record = { type: "normal", arg: innerFn.call(self, context) }; if (record.type === "normal") { state = context.done ? "completed" : "yield"; if (record.arg === ContinueSentinel) { continue; } return { value: record.arg, done: context.done }; } } }; } window.regeneratorRuntime = {}; regeneratorRuntime.wrap = wrap; regeneratorRuntime.mark = mark; })(); "use strict"; function _asyncToGenerator(fn) { return function() { var gen = fn.apply(this, arguments); return new Promise(function(resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then( function(value) { step("next", value); }, function(err) { step("throw", err); } ); } } return step("next"); }); }; } var fetchData = function fetchData(data) { return new Promise(function(resolve) { return setTimeout(resolve, 1000, data + 1); }); }; var fetchValue = (function() { var _ref = _asyncToGenerator( /*#__PURE__*/ regeneratorRuntime.mark(function _callee() { var value1, value2, value3; return regeneratorRuntime.wrap( function _callee$(_context) { while (1) { switch ((_context.prev = _context.next)) { case 0: _context.next = 2; return fetchData(1); case 2: value1 = _context.sent; _context.next = 5; return fetchData(value1); case 5: value2 = _context.sent; _context.next = 8; return fetchData(value2); case 8: value3 = _context.sent; console.log(value3); case 10: case "end": return _context.stop(); } } }, _callee, this ); }) ); return function fetchValue() { return _ref.apply(this, arguments); }; })(); fetchValue();
請原諒我水了一篇文章……
ES6 系列ES6 系列目錄地址:https://github.com/mqyqingfeng/Blog
ES6 系列預計寫二十篇左右,旨在加深 ES6 部分知識點的理解,重點講解塊級作用域、標簽模板、箭頭函數、Symbol、Set、Map 以及 Promise 的模擬實現、模塊加載方案、異步處理等內容。
如果有錯誤或者不嚴謹的地方,請務必給予指正,十分感謝。如果喜歡或者有所啟發,歡迎 star,對作者也是一種鼓勵。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/98892.html
摘要:前言本文就是簡單介紹下語法編譯后的代碼。如果有錯誤或者不嚴謹的地方,請務必給予指正,十分感謝。如果喜歡或者有所啟發,歡迎,對作者也是一種鼓勵。 前言 本文就是簡單介紹下 Generator 語法編譯后的代碼。 Generator function* helloWorldGenerator() { yield hello; yield world; return ending...
摘要:上集回顧從零開始手把手教你實現一個一上一集我們介紹了什么是,為什么要用,以及我們要怎樣來實現一個。完成后,在命令行中輸入安裝下依賴。最后返回這個目標節點。明天,我們迎接挑戰,開始處理數據變動引起的重新渲染,我們要如何新舊,生成補丁,修改。 上集回顧 從零開始手把手教你實現一個Virtual DOM(一)上一集我們介紹了什么是VDOM,為什么要用VDOM,以及我們要怎樣來實現一個VDOM...
摘要:塊級作用域存在于函數內部塊中字符和之間的區域和塊級聲明用于聲明在指定塊的作用域之外無法訪問的變量。和都是塊級聲明的一種。值得一提的是聲明不允許修改綁定,但允許修改值。這意味著當用聲明對象時沒有問題報錯臨時死區臨時死區,簡寫為。 塊級作用域的出現 通過 var 聲明的變量存在變量提升的特性: if (condition) { var value = 1; } console.lo...
摘要:聲明的變量不得改變值,這意味著,一旦聲明變量,就必須立即初始化,不能留到以后賦值。這在語法上,稱為暫時性死區,簡稱。這表明函數內部的變量與循環變量不在同一個作用域,有各自單獨的作用域。系列文章系列文章地址 showImg(https://segmentfault.com/img/bVbrjjC); 為什么需要塊級作用域 ES5 只有全局作用域和函數作用域,沒有塊級作用域,這帶來很多不合...
摘要:簡單的說就是,新語法編譯器舊語法。說明所以,對于新特性,我們可以通過使用,也可以通過語法轉化來達到兼容。 0x001 polyfill 我們都知道,js總是一直存在著兼容性問題,雖然其他語言也存在著兼容性問題,比如c++、java,但那種兼容性是新特性在舊版本上的不兼容,js則存在著各種奇形怪哉的不兼容。這其中有著非常復雜的歷史和時代的原因,并不加以累述。而解決兼容性問題的方法在以前只...
閱讀 2337·2021-11-24 11:16
閱讀 2022·2021-09-30 09:47
閱讀 1997·2021-09-10 10:51
閱讀 1316·2019-08-30 14:08
閱讀 3133·2019-08-30 13:47
閱讀 1522·2019-08-30 13:02
閱讀 3227·2019-08-29 12:29
閱讀 3179·2019-08-26 17:05