JS迭代器及异步

2023-10-16 06:12
文章标签 js 异步 器及 迭代

本文主要是介绍JS迭代器及异步,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

 可迭代对象及其相关的迭代器是ES6的一个特性。ES6新增的期约让编写异步代码更容易。关键字async和await是ES2017中引入的,为了简化异步编程提供的新语法,最后,异步迭代器和for/aswait循环是ES2018中引入的,允许在看起来同步的简单循环中操作异步事件流。

1 迭代器与生成器

迭代器3个不同类型:

1)可迭代对象,指的是任何具有专用迭代器方法,且该方法返回迭代器对象的对象。

2)迭代器对象,指的是任何具有next()方法,且该方法返回迭代结果对象的对象。

3)迭代结果对象,具有属性value和done的对象。

可迭代对象的迭代器方法没有使用惯用名称,而是使用了符号Symbol.iterator作为名字。

迭代器本身也是可迭代的。(它们也有Symbol.iterator方法,且返回它们自己。)

1.1 实现可迭代对象

function names() {

    let nameArr = ["Tom","Jerry","Lucy"];
    let current = 0;

    return {
        [Symbol.iterator]() {
            return this;
        },
        next() {
            if (current < nameArr.length) {
                return {value: nameArr[current++],done: false};
            }
            return { done: true };
        },
        return() {
            console.log("迭代器被终止了");
            return {done: true};
        }
    }

}

let iterator = names();
for (let it of iterator) {
    if (it === "Jerry") break;
    console.log(it);
}
// Tom
// 迭代器被终止了

迭代器的return()方法,如果迭代在next()方法done属性为true的结果前停止(常见原因是通过break语句提前退出for/of循环),那么解释器会检查迭代器对象是否有return()方法,如果有,则会调用它。这个return()方法必须返回一个迭代器结果对象,这个对象的属性会被忽略,但返回非对象值会导致报错。

1.2 生成器

语法上类似常规的JS函数,但使用关键字是function*。调用生成器并不会实际执行函数体,而是返回一个生成器对象(是一个迭代器)。调用它的next()方法会导致生成器函数的函数体从头(或从当前位置)开始执行,直至遇见一个yield语句。yield语句的值会成为调用迭代器的next()方法的返回值。

function* numIterator() {
    console.log("numIterator begin");
    yield 1;
    console.log("yield 1 finished");
    yield 2;
    console.log("yield 2 finished");
    yield 3;
    console.log("yield 3 finished");
    console.log("numIterator begin")
}

let iterator = numIterator();
iterator.next(); // numIterator begin
iterator.next(); // yield 1 finished
iterator.next(); // yield 2 finished
iterator.next(); // yield 3 finished numIterator begin
iterator.next(); // 空输出

1.3 高级生成器特性

1)生成器函数的返回值。生成器函数可以有return语句,只是其返回值在迭代的时候会被忽略。但是手工迭代时可通过显示调用next()得到:

function* numIterator() {
    yield 1;
    yield 2;
    return "hello";
}

console.log(...numIterator()); // 1 2
let iterator = numIterator();
console.log(iterator.next()); // { value: 1, done: false }
console.log(iterator.next()); // { value: 2, done: false }
console.log(iterator.next()); // { value: 'hello', done: true }
console.log(iterator.next()); // { value: undefined, done: true }

2)yield表达式的值。yield是一个表达式,可以有值的。调用生成器next()方法时,生成器函数会一直运行直到到达一个yield表达式,yield关键字后面的表达式会被求值,该值成为next()调用的返回值。此时生成器函数在求值yield表达式中途停了下来。下次调用生成器的next()方法时,传给next()的参数会变成暂停的yield表达式的值。

function* numIterator() {
    console.log("begin");
    let y1 = yield 1;
    console.log("y1:",y1);
    let y2 = yield 2;
    console.log("y2:",y2);
}

let iterator = numIterator();
iterator.next("a"); // begin
iterator.next("b"); // y1:b
iterator.next("c"); // y2:c

3)生成器的try/finally。在实现迭代器对象时可定义return()方法,但是在生成器不行,但是生成器可以通过try/ finally来实现同等效果。

function* numIterator() {
    try{
        yield 1;
        yield 2;
        yield 3;
    } finally {
        console.log("迭代")
    }
}

console.log(...numIterator());// 迭代 1 2 3
for (let it of numIterator()) {
    console.log(it);
}
// 迭代
// 1 2 3
// 1
// 2
// 3
// 迭代

2 异步JS

期约是一种为简化异步编程而设计的核心语言特性。

2.1 期约 Promise

       期约是一个对象,表示异步操作的结果。这个结果可能就绪也可能未就绪。

以动词开头来命名返回期约的函数是一种惯例。

function customPro() {
    console.log("异步函数");
    return new Promise((resolve,reject) => {
        resolve("hello 回调函数");
    });
}

function showCallBackInfo(res) {
    console.log("回调1",res);
}

customPro().then(showCallBackInfo);
// 异步函数
// 回调1 hello 回调函数

2.1.1 处理错误

期约有两种处理错误的方式:

1)then()第二个参数传递一个处理错误的函数。

2)catch()方法。

function customPromise(type) {
    console.log("异步函数");
    return  new Promise((resolve,reject) => {
        if (type % 2 === 0) {
            resolve(type % 2);
        } else {
            reject(new Error("不能为基数"));
        }
    });
}

function showCallBackInfo(type) {
    console.log("回调函数:" + type)
}

function catchError(e) {
    console.log(e);
}

customPromise(1).then(showCallBackInfo,catchError); // 异步函数 Error: 不能为基数 (报错)
customPromise(0).then(showCallBackInfo,catchError); // 异步函数 回调函数:0
customPromise(1).then(showCallBackInfo).catch(catchError); // 异步函数 Error: 不能为基数 (报错)

catch(),会捕获期约链上在它位置前面所有期约的错误(如果该期约的错误没被处理的话)。

fun().then(call1).then(call2).catch(errCatch); //catch会捕获fun、call1的错误。

fun().then(call1).catch(errCatch1).then(call2).catch(errCatch2); //errCatch2只会捕获call1的错误,因为fun的错误已被errCatch1捕获并处理(未抛出)。

2.1.2 并行期约

1) Promise.all()接收一个期约对象数组作为输入,返回一个期约。如果输入期约中任意一个拒绝,返回的期约也将拒绝;否则,返回期约会以每个输入期约兑现值的数组兑现。

2)Promise.allSettled()接收一个期约对象数组作为输入,永远不拒绝返回的期约,会等所有输入期约全部落定后兑现。其返回的期约解决为一个对象数组,其中每个对象都应对应一个输入期约,且都有一个status属性,值为fulfilled或rejected,如果status属性值为fulfilled,值该对象还有个value属性,包含兑现的值。如果status为rejected,那该对象还有个reason属性。

3)Promise.race(),接收一个期约对象数组作为输入,返回一个期约,这个期约会在输入数组中的期约有一个兑现或拒绝时马上兑现或拒绝。

2.1.3 创建期约

1)从头开始创建期约。

function customPromise(type) {
    console.log("自定义异步函数");
    // 创建新期约
    return new Promise((resolve,reject) => {
        if (type < 0) reject(new Error("不能小于0"));
        else resolve("你好啊");
    });
}

function showCallBackInfo(info) {
    console.log(info);
}

function dealErr(error) {
    console.log(error.message);
}
customPromise(2).then(showCallBackInfo).catch(dealErr);
customPromise(-1).then(showCallBackInfo).catch(dealErr);
// 自定义异步函数
// 自定义异步函数
// 你好啊
// 不能小于0

2)基于其他期约的期约。

function customPromise() {
    return new Promise((resolve) => {
        resolve();
    })
}

function customPromise2() {
    return customPromise().then(_ => "hello");
}

customPromise2().then(res => {
    console.log("res:",res); //res:hello
})

3)基于同步值的期约。

Promise.resolve() 接收一个值作为参数,并会立即(异步)以该值兑现一个期约。Promise.reject()则返回以该参数作为理由而拒绝的期约。

Promise.resolve("hello").then(res => {
    console.log("res:",res); // res: hello
})

2.2 async 和 await

ES2017 新增了async和await两个关键字。

function sleep(time) {
    return new Promise(resolve => setTimeout(resolve,time * 1000))
}

async function countDown() {
    let begin = new Date();
    console.log("开始");
    await sleep(1);
    await sleep(2);
    await sleep(2);
    let end = new Date();
    console.log("结束");
    return end.getTime() - begin.getTime();
}

countDown().then(time => {
    console.log("耗时:" + time / 1000 + "s");
});
// 开始
// 结束
// 耗时:5.009s

实现细节,编译器将async函数包装成一个返回期约的函数。

这篇关于JS迭代器及异步的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/219599

相关文章

Java集合之Iterator迭代器实现代码解析

《Java集合之Iterator迭代器实现代码解析》迭代器Iterator是Java集合框架中的一个核心接口,位于java.util包下,它定义了一种标准的元素访问机制,为各种集合类型提供了一种统一的... 目录一、什么是Iterator二、Iterator的核心方法三、基本使用示例四、Iterator的工

Python爬虫HTTPS使用requests,httpx,aiohttp实战中的证书异步等问题

《Python爬虫HTTPS使用requests,httpx,aiohttp实战中的证书异步等问题》在爬虫工程里,“HTTPS”是绕不开的话题,HTTPS为传输加密提供保护,同时也给爬虫带来证书校验、... 目录一、核心问题与优先级检查(先问三件事)二、基础示例:requests 与证书处理三、高并发选型:

JS纯前端实现浏览器语音播报、朗读功能的完整代码

《JS纯前端实现浏览器语音播报、朗读功能的完整代码》在现代互联网的发展中,语音技术正逐渐成为改变用户体验的重要一环,下面:本文主要介绍JS纯前端实现浏览器语音播报、朗读功能的相关资料,文中通过代码... 目录一、朗读单条文本:① 语音自选参数,按钮控制语音:② 效果图:二、朗读多条文本:① 语音有默认值:②

在Node.js中使用.env文件管理环境变量的全过程

《在Node.js中使用.env文件管理环境变量的全过程》Node.js应用程序通常依赖于环境变量来管理敏感信息或配置设置,.env文件已经成为一种流行的本地管理这些变量的方法,本文将探讨.env文件... 目录引言为什么使php用 .env 文件 ?如何在 Node.js 中使用 .env 文件最佳实践引

使用Node.js和PostgreSQL构建数据库应用

《使用Node.js和PostgreSQL构建数据库应用》PostgreSQL是一个功能强大的开源关系型数据库,而Node.js是构建高效网络应用的理想平台,结合这两个技术,我们可以创建出色的数据驱动... 目录初始化项目与安装依赖建立数据库连接执行CRUD操作查询数据插入数据更新数据删除数据完整示例与最佳

Three.js构建一个 3D 商品展示空间完整实战项目

《Three.js构建一个3D商品展示空间完整实战项目》Three.js是一个强大的JavaScript库,专用于在Web浏览器中创建3D图形,:本文主要介绍Three.js构建一个3D商品展... 目录引言项目核心技术1. 项目架构与资源组织2. 多模型切换、交互热点绑定3. 移动端适配与帧率优化4. 可

Python异步编程之await与asyncio基本用法详解

《Python异步编程之await与asyncio基本用法详解》在Python中,await和asyncio是异步编程的核心工具,用于高效处理I/O密集型任务(如网络请求、文件读写、数据库操作等),接... 目录一、核心概念二、使用场景三、基本用法1. 定义协程2. 运行协程3. 并发执行多个任务四、关键

C#异步编程ConfigureAwait的使用小结

《C#异步编程ConfigureAwait的使用小结》本文介绍了异步编程在GUI和服务器端应用的优势,详细的介绍了async和await的关键作用,通过实例解析了在UI线程正确使用await.Conf... 异步编程是并发的一种形式,它有两大好处:对于面向终端用户的GUI程序,提高了响应能力对于服务器端应

C# async await 异步编程实现机制详解

《C#asyncawait异步编程实现机制详解》async/await是C#5.0引入的语法糖,它基于**状态机(StateMachine)**模式实现,将异步方法转换为编译器生成的状态机类,本... 目录一、async/await 异步编程实现机制1.1 核心概念1.2 编译器转换过程1.3 关键组件解析

如何在Java Spring实现异步执行(详细篇)

《如何在JavaSpring实现异步执行(详细篇)》Spring框架通过@Async、Executor等实现异步执行,提升系统性能与响应速度,支持自定义线程池管理并发,本文给大家介绍如何在Sprin... 目录前言1. 使用 @Async 实现异步执行1.1 启用异步执行支持1.2 创建异步方法1.3 调用