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

相关文章

Redis消息队列实现异步秒杀功能

《Redis消息队列实现异步秒杀功能》在高并发场景下,为了提高秒杀业务的性能,可将部分工作交给Redis处理,并通过异步方式执行,Redis提供了多种数据结构来实现消息队列,总结三种,本文详细介绍Re... 目录1 Redis消息队列1.1 List 结构1.2 Pub/Sub 模式1.3 Stream 结

使用Python实现一个优雅的异步定时器

《使用Python实现一个优雅的异步定时器》在Python中实现定时器功能是一个常见需求,尤其是在需要周期性执行任务的场景下,本文给大家介绍了基于asyncio和threading模块,可扩展的异步定... 目录需求背景代码1. 单例事件循环的实现2. 事件循环的运行与关闭3. 定时器核心逻辑4. 启动与停

C#中async await异步关键字用法和异步的底层原理全解析

《C#中asyncawait异步关键字用法和异步的底层原理全解析》:本文主要介绍C#中asyncawait异步关键字用法和异步的底层原理全解析,本文给大家介绍的非常详细,对大家的学习或工作具有一... 目录C#异步编程一、异步编程基础二、异步方法的工作原理三、代码示例四、编译后的底层实现五、总结C#异步编程

JS+HTML实现在线图片水印添加工具

《JS+HTML实现在线图片水印添加工具》在社交媒体和内容创作日益频繁的今天,如何保护原创内容、展示品牌身份成了一个不得不面对的问题,本文将实现一个完全基于HTML+CSS构建的现代化图片水印在线工具... 目录概述功能亮点使用方法技术解析延伸思考运行效果项目源码下载总结概述在社交媒体和内容创作日益频繁的

Node.js 数据库 CRUD 项目示例详解(完美解决方案)

《Node.js数据库CRUD项目示例详解(完美解决方案)》:本文主要介绍Node.js数据库CRUD项目示例详解(完美解决方案),本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考... 目录项目结构1. 初始化项目2. 配置数据库连接 (config/db.js)3. 创建模型 (models/

使用Node.js制作图片上传服务的详细教程

《使用Node.js制作图片上传服务的详细教程》在现代Web应用开发中,图片上传是一项常见且重要的功能,借助Node.js强大的生态系统,我们可以轻松搭建高效的图片上传服务,本文将深入探讨如何使用No... 目录准备工作搭建 Express 服务器配置 multer 进行图片上传处理图片上传请求完整代码示例

Python 迭代器和生成器概念及场景分析

《Python迭代器和生成器概念及场景分析》yield是Python中实现惰性计算和协程的核心工具,结合send()、throw()、close()等方法,能够构建高效、灵活的数据流和控制流模型,这... 目录迭代器的介绍自定义迭代器省略的迭代器生产器的介绍yield的普通用法yield的高级用法yidle

C++变换迭代器使用方法小结

《C++变换迭代器使用方法小结》本文主要介绍了C++变换迭代器使用方法小结,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录1、源码2、代码解析代码解析:transform_iterator1. transform_iterat

用js控制视频播放进度基本示例代码

《用js控制视频播放进度基本示例代码》写前端的时候,很多的时候是需要支持要网页视频播放的功能,下面这篇文章主要给大家介绍了关于用js控制视频播放进度的相关资料,文中通过代码介绍的非常详细,需要的朋友可... 目录前言html部分:JavaScript部分:注意:总结前言在javascript中控制视频播放

Python 中的异步与同步深度解析(实践记录)

《Python中的异步与同步深度解析(实践记录)》在Python编程世界里,异步和同步的概念是理解程序执行流程和性能优化的关键,这篇文章将带你深入了解它们的差异,以及阻塞和非阻塞的特性,同时通过实际... 目录python中的异步与同步:深度解析与实践异步与同步的定义异步同步阻塞与非阻塞的概念阻塞非阻塞同步