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