JavaScript 异步编程(太棒了)。





5.00/5 (20投票s)
Microsoft 项目经理 David Cathuhe 分享了关于 ECMAScript 中异步代码的概述:它是什么,如何工作,以及它如何改进你在 JavaScript 工作流。
JavaScript 自早期版本以来已经取得了长足的进步,这要归功于 TC39(负责标准化 JavaScript(或更准确地说是 ECMAScript)的组织)所做的所有努力,我们现在拥有了一种被广泛使用的现代语言。
ECMAScript 中获得巨大改进的一个领域是异步代码。如果你是新手开发者,你可以在 这里 了解更多关于异步编程的知识。幸运的是,我们在 Windows 10 的新 Edge 浏览器中包含了这些更改——请查看 Microsoft Edge 更新日志。
在所有这些新功能中,让我们特别关注“ES2016 Async Functions”(在实验性 JavaScript 功能标志后面),并一起探索更新,看看 ECMAScript 如何改进你当前的工作流程。
第一站:ECMAScript 5 – 回调城市
ECMAScript 5(以及之前的版本)都围绕着回调。为了更好地说明这一点,让我们举一个你每天肯定会使用不止一次的简单例子:执行 XHR 请求。
var displayDiv = document.getElementById("displayDiv"); // Part 1 - Defining what do we want to do with the result var processJSON = function (json) { var result = JSON.parse(json); result.collection.forEach(function(card) { var div = document.createElement("div"); div.innerHTML = card.name + " cost is " + card.price; displayDiv.appendChild(div); }); } // Part 2 - Providing a function to display errors var displayError = function(error) { displayDiv.innerHTML = error; } // Part 3 - Creating and setting up the XHR object var xhr = new XMLHttpRequest(); xhr.open('GET', "cards.json"); // Part 4 - Defining callbacks that XHR object will call for us xhr.onload = function(){ if (xhr.status === 200) { processJSON(xhr.response); } } xhr.onerror = function() { displayError("Unable to load RSS"); } // Part 5 - Starting the process xhr.send();
经验丰富的 JavaScript 开发人员会注意到这看起来多么熟悉,因为 XHR 回调一直都在使用!它很简单,而且相当直接:开发人员创建一个 XHR 请求,然后为指定的 XHR 对象提供回调。
相比之下,由于异步代码的内在特性,回调的复杂性来自于其非线性的执行顺序。
当在自己的回调中使用另一个异步调用时,“回调地狱”会变得更加糟糕。
第二站:ECMAScript 6 – Promise 城市
ECMAScript 6 正在获得势头,Edge 在支持方面处于领先地位,迄今为止覆盖率达到 88%。
在许多重大改进中,ECMAScript 6 标准化了Promise(以前称为 future)的使用。
根据 MDN 的说法,Promise 是一个用于延迟和异步计算的对象。Promise 代表一个尚未完成但预期在未来完成的操作。Promise 是一种组织异步操作的方式,使其看起来像同步操作。这正是我们 XHR 示例所需要的。
Promise 已经存在一段时间了,但好消息是现在你不再需要任何库,因为浏览器已经提供了它们。
让我们稍微更新一下我们的示例以支持Promise,看看它如何改进我们代码的可读性和可维护性。
var displayDiv = document.getElementById("displayDiv"); // Part 1 - Create a function that returns a promise function getJsonAsync(url) { // Promises require two functions: one for success, one for failure return new Promise(function (resolve, reject) { var xhr = new XMLHttpRequest(); xhr.open('GET', url); xhr.onload = () => { if (xhr.status === 200) { // We can resolve the promise resolve(xhr.response); } else { // It's a failure, so let's reject the promise reject("Unable to load RSS"); } } xhr.onerror = () => { // It's a failure, so let's reject the promise reject("Unable to load RSS"); }; xhr.send(); }); } // Part 2 - The function returns a promise // so we can chain with a .then and a .catch getJsonAsync("cards.json").then(json => { var result = JSON.parse(json); result.collection.forEach(card => { var div = document.createElement("div"); div.innerHTML = `${card.name} cost is ${card.price}`; displayDiv.appendChild(div); }); }).catch(error => { displayDiv.innerHTML = error; });
你可能已经注意到了很多改进。让我们仔细看看。
创建 Promise
为了“Promise 化”(抱歉,我是法国人,所以我可以发明新词)旧的 XHR 对象,你需要创建一个 Promise
对象。
使用 Promise
创建后,Promise 可以用于以更优雅的方式链接异步调用。
所以现在(从用户的角度来看)我们有:
- 获取 Promise (1)
- 链接成功代码 (2 和 3)
- 链接错误代码 (4),就像在 try/catch 块中一样。
有趣的是,链接Promise 可以很容易地通过.then().then() 等方式调用。
旁注:由于 JavaScript 是一门现代语言,你可能会注意到我还使用了 ECMAScript 6 的语法糖,如模板字符串 或箭头函数。
终点:ECMAScript 7 – 异步城市
终于,我们到达了目的地!我们几乎已经到达未来,但得益于 Edge 快速的开发周期,团队能够在最新版本中引入一点ECMAScript 7 的async functions!
Async functions 是一种语法糖,用于改进编写异步代码的语言级模型。
Async functions 构建在 ECMAScript 6 功能(如生成器)之上。事实上,生成器可以与 Promise 结合使用以产生相同的结果,但需要更多的用户代码。
我们不需要更改生成 Promise 的函数,因为 async functions 可以直接与 Promise 一起工作。
我们只需要更改调用函数。
// Let's create an async anonymous function (async function() { try { // Just have to await the promise! var json = await getJsonAsync("cards.json"); var result = JSON.parse(json); result.collection.forEach(card => { var div = document.createElement("div"); div.innerHTML = `${card.name} cost is ${card.price}`; displayDiv.appendChild(div); }); } catch (e) { displayDiv.innerHTML = e; } })();
这就是魔法发生的地方。这段代码看起来像普通的同步代码,具有完美的线性执行路径。
相当令人印象深刻,对吧?
好消息是,你甚至可以将 async functions 与箭头函数或类方法一起使用。
深入研究
如果你想了解更多关于我们在 Chakra 中如何实现它的细节,请查看 Microsoft Edge 博客上的官方帖子。你还可以使用 Kangax 的网站跟踪各种浏览器实现ECMAScript 6 和7 的进度。
也请随时查看我们的 JavaScript 路线图!请不要犹豫,通过使用投票按钮来提供你的反馈并支持你喜欢的特性。
感谢阅读,我们期待听到你的反馈和想法!
更多 Web 开发实践
本文是 Microsoft 技术布道师和工程师关于实用 JavaScript 学习、开源项目和互操作性最佳实践的 Web 开发系列的一部分,包括 Microsoft Edge 浏览器和新的 EdgeHTML 渲染引擎。
我们鼓励你在包括 Microsoft Edge(Windows 10 的默认浏览器)在内的各种浏览器和设备上进行测试,可以使用 dev.modern.IE 上的免费工具。
- 扫描您的网站是否存在过时库、布局问题和可访问性问题
- 将虚拟机用于 Mac、Linux 和 Windows
- 在您自己的设备上远程测试 Microsoft Edge
- GitHub 上的编程实验室:跨浏览器测试和最佳实践
深入了解 Microsoft Edge 和 Web 平台的技术学习
- Microsoft Edge Web Summit 2015(关于新浏览器、新支持的 Web 平台标准以及来自 JavaScript 社区的特邀演讲者)。
- 哇,我可以在 Mac 和 Linux 上测试 Edge 和 IE!(来自 Rey Bango)
- 在不破坏 Web 的前提下推进 JavaScript(来自 Christian Heilmann)
- 让 Web 正常工作的 Edge 渲染引擎(来自 Jacob Rossi)
- 使用 WebGL 释放 3D 渲染功能(来自 David Catuhe,包括 vorlon.JS 和 babylonJS 项目)
- 托管 Web 应用和 Web 平台创新(来自 Kevin Hill 和 Kiril Seksenov,包括 manifold.JS 项目)
更多免费的跨平台工具和网络平台资源
- 适用于 Linux、MacOS 和 Windows 的 Visual Studio Code
- 使用 Node.JS 编码,并在 Azure 上免费试用。