Async

xiaoxiao2021-02-28  20

ECMAScript 2017 Async Functions(异步函数)。 ##今天被萌神鄙视了说我写的blog丑所以我就开始用markdown学习并且使用markdown开始写一篇文章试下

###async各种不同的定义方式 异步函数声明: async function foo() {} 异步函数表达式: const foo = async function () {}; 异步函数定义:let obj = { async foo() {} } 异步箭头函数: const foo = async () => {};

###async(异步) 函数总是返回 Promises

async(异步) 函数的 Promise 完成状态:

async function asyncFunc() { return 123; } asyncFunc() .then(x => console.log(x)); // 123

async(异步) 函数的 Promise 拒绝状态:

async function asyncFunc() { throw new Error('Problem!'); } asyncFunc() .catch(err => console.log(err)); // Error: Problem!

###通过 await 处理 async(异步) 计算的结果和错误

await(只允许在 async(异步) 函数内部使用)等待其操作对象 Promise返回

如果 Promise 是完成状态,await 的结果是完成态的值。如果 Promise 是拒绝状态,await 会抛出拒绝值。

处理单个 async(异步) 返回值:

async function asyncFunc() { const result = await otherAsyncFunc(); console.log(result); } // 等价于: function asyncFunc() { return otherAsyncFunc() .then(result => { console.log(result); }); }

按顺序处理多个 async(异步) 返回值

async function asyncFunc() { const result1 = await otherAsyncFunc1(); console.log(result1); const result2 = await otherAsyncFunc2(); console.log(result2); } // 等价于: function asyncFunc() { return otherAsyncFunc1() .then(result1 => { console.log(result1); return otherAsyncFunc2(); }) .then(result2 => { console.log(result2); }); }

并行处理多个 async(异步) 返回值:

async function asyncFunc() { const [result1, result2] = await Promise.all([ otherAsyncFunc1(), otherAsyncFunc2(), ]); console.log(result1, result2); } // 等价于: function asyncFunc() { return Promise.all([ otherAsyncFunc1(), otherAsyncFunc2(), ]) .then([result1, result2] => { console.log(result1, result2); }); }

错误处理:

async function asyncFunc() { try { await otherAsyncFunc(); } catch (err) { console.error(err); } } // 等价于: function asyncFunc() { return otherAsyncFunc() .catch(err => { console.error(err); }); }

##理解 async(异步) 函数 在我解释 async(异步) 函数之前,我需要解释一下如何组合使用 Promises 和 Generator ,通过看起来同步的代码来执行 async(异步) 操作。

对于能够 async(异步) 计算其一次性结果的函数,作为 ES6 一部分的 Promises 已经变得流行起来。一个例子是 客户端 fetch API ,它是 XMLHttpRequest 获取数据的替代方法。使用示例如下:

function fetchJson(url) { return fetch(url) .then(request => request.text()) .then(text => { return JSON.parse(text); }) .catch(error => { console.log(`ERROR: ${error.stack}`); }); } fetchJson('http://example.com/some_file.json') .then(obj => console.log(obj));

###通过 generator 来编写异步代码 co 是一个使用 Promise 和 generator 来实现看似同步编码的库,但与上一示例中使用的样式相同:

const fetchJson = co.wrap(function* (url) { try { let request = yield fetch(url); let text = yield request.text(); return JSON.parse(text); } catch (error) { console.log(`ERROR: ${error.stack}`); } });

每次回调函数( generator 函数)产生一个 Promise 对象给 co ,回调会被暂停,只有当 Promise 执行完成后,co 才会继续执行回调 。 如果 Promise 处于完成状态,yield 返回完成状态的值,如果处于拒绝状态,yield 抛出拒绝状态的错误。此外,co 保证结果是通过回调执行完成才返回的(类似于 then() 所做的工作)。 ###通过 async(异步) 函数来编写异步代码 async(异步) 函数用的特定语法基本上和 co 类似:

async function fetchJson(url) { try { let request = await fetch(url); let text = await request.text(); return JSON.parse(text); } catch (error) { console.log(`ERROR: ${error.stack}`); } }

在内部,异步函数写法更类似于 generators ###以同步开始,异步处理的 async(异步) 函数

以下是 async(异步)函数是如何工作的:

async(异步) 函数总是返回一个 Promise 对象 p 。Promise 对象在 async(异步) 函数开始执行时被创建函数体执行过程中,可以通过可以通过 return 或 throw 终止执行。或者通过 await 暂停执行,在这种情况下,通常会在以后继续执行。返回 Promise 对象 p。

当执行 async(异步) 函数的函数体时,return x 中的 x 是 Promise 对象 p 的完成状态的结果,而 throw err 是 p 的拒绝状态的结果。执行结果是异步返回的。换句话说:then() 和 catch() 的回调总是在当前代码完成后执行。

以下是代码示例:

async function asyncFunc() { console.log('asyncFunc()'); // (A) return 'abc'; } asyncFunc(). then(x => console.log(`Resolved: ${x}`)); // (B) console.log('main'); // (C) // Output: // asyncFunc() // main // Resolved: abc 行A:async(异步) 函数以同步开始。async(异步) 函数的 Promise 通过 return 来返回完成状态的结果。行C:执行继续。行B:Promise 完成状态通知是异步发生的。

###返回不被包裹的 Promise 对象 Promise 的 resolve 是一项标准操作。 return 就是使用它来 resolve async(异步) 函数的 Promise p 的。这意味着:

返回一个非 Promise 值,该值将被处理成 p 的完成状态值。返回一个 Promise 对象,那么 p 此时相当于是该 Promise 的状态。 因此,您可以返回一个 Promise ,并且这个 Promise 不会包裹在别的 Promise 中: async function asyncFunc() { return Promise.resolve(123); } asyncFunc() .then(x => console.log(x)) // 123

有趣的是,返回一个拒绝状态(reject)的 Promise 对象会导致 async(异步) 函数被拒绝(reject)(通常,您可以使用 throw ):

async function asyncFunc() { return Promise.reject(new Error('Problem!')); } asyncFunc() .catch(err => console.error(err)); // Error: Problem!

这与 Promise 解决方案的工作方式是一致的。 使你能够在不使用 await 的情况下,使用其他 async(异步) 计算来执行完成和拒绝处理:

async function asyncFunc() { return anotherAsyncFunc(); }

上面的代码示例和下面的类似,但是比下面的更高效。(以下代码示例没有包裹 anotherAsyncFunc() 的 Promise ,而是包裹 anotherAsyncFunc() 本身 ):

async function asyncFunc() { return await anotherAsyncFunc(); }

###await 是顺序执行的,Promise.all() 是并行的 下面的代码调用了两个 async(异步) 函数, asyncFunc1() 和 asyncFunc1() 。

async function foo() { const result1 = await asyncFunc1(); const result2 = await asyncFunc2(); }

这两个函数调用顺序执行。但是并行执行它们往往会加快速度。您可以使用 Promise.all()

async function foo() { const [result1, result2] = await Promise.all([ asyncFunc1(), asyncFunc2(), ]); }

我们现在正在等待一个包含两个元素的数组的 Promise ,而不是等待两个 Promise。 ###异步函数和回调 async(异步) 函数的一个限制是 await(等待) 只影响直接相关的 async(异步) 函数。因此,async(异步) 函数无法在回调(但是,回调可以是 async(异步) 函数本身,稍后我们将会看到)中使用 await(等待)。这使得基于回调的实用函数和方法难以使用。例子中我们将使用数组方法 map() 和 forEach() 。 ####Array.prototype.map() ####Array.prototype.forEach()

###了解你的 Promises async(异步) 函数的基础就是 Promises 对象,这就是为什么理解 Promises 对于理解 async(异步) 函数至关重要。特别是当遇到不是基于 Promises 的老代码来实现 async(异步) 函数时,你通常别无选择,只能用 Promise 来重构。

举个例子,这里有个 “promisified” 版本的XMLHttpRequest:

function httpGet(url, responseType="") { return new Promise( function (resolve, reject) { const request = new XMLHttpRequest(); request.onload = function () { if (this.status === 200) { // Success resolve(this.response); } else { // Something went wrong (404 etc.) reject(new Error(this.statusText)); } }; request.onerror = function () { reject(new Error( 'XMLHttpRequest Error: '+this.statusText)); }; request.open('GET', url); xhr.responseType = responseType; request.send(); }); }

XMLHttpRequest 的 API 是基于回调的。通过一个 async(异步) 函数来实现它,意味着你必须在回调中返回 Promise 的完成(fulfill) 或拒绝(reject) 状态。这是不可能的,因为你只能通过 return 或者 throw 来完成这样的操作。你不能从回调函数内部 return 一个函数的结果。throw也有类似的约束。 因此,异步函数的通用编码风格是:

直接使用 Promise 对象来构建异步原语。用异步函数来使用这些原语。

http://www.css88.com/archives/7731

转载请注明原文地址: https://www.6miu.com/read-1450246.html

最新回复(0)