Async

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

猜你喜欢

转载自blog.csdn.net/wen_binobject/article/details/79699560