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

相关文章

使用Python获取JS加载的数据的多种实现方法

《使用Python获取JS加载的数据的多种实现方法》在当今的互联网时代,网页数据的动态加载已经成为一种常见的技术手段,许多现代网站通过JavaScript(JS)动态加载内容,这使得传统的静态网页爬取... 目录引言一、动态 网页与js加载数据的原理二、python爬取JS加载数据的方法(一)分析网络请求1

C++迭代器失效的避坑指南

《C++迭代器失效的避坑指南》在C++中,迭代器(iterator)是一种类似指针的对象,用于遍历STL容器(如vector、list、map等),迭代器失效是指在对容器进行某些操作后... 目录1. 什么是迭代器失效?2. 哪些操作会导致迭代器失效?2.1 vector 的插入操作(push_back,

Android NDK版本迭代与FFmpeg交叉编译完全指南

《AndroidNDK版本迭代与FFmpeg交叉编译完全指南》在Android开发中,使用NDK进行原生代码开发是一项常见需求,特别是当我们需要集成FFmpeg这样的多媒体处理库时,本文将深入分析A... 目录一、android NDK版本迭代分界线二、FFmpeg交叉编译关键注意事项三、完整编译脚本示例四

VSCode中配置node.js的实现示例

《VSCode中配置node.js的实现示例》本文主要介绍了VSCode中配置node.js的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着... 目录一.node.js下载安装教程二.配置npm三.配置环境变量四.VSCode配置五.心得一.no

Python 异步编程 asyncio简介及基本用法

《Python异步编程asyncio简介及基本用法》asyncio是Python的一个库,用于编写并发代码,使用协程、任务和Futures来处理I/O密集型和高延迟操作,本文给大家介绍Python... 目录1、asyncio是什么IO密集型任务特征2、怎么用1、基本用法2、关键字 async1、async

嵌入式Linux驱动中的异步通知机制详解

《嵌入式Linux驱动中的异步通知机制详解》:本文主要介绍嵌入式Linux驱动中的异步通知机制,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录前言一、异步通知的核心概念1. 什么是异步通知2. 异步通知的关键组件二、异步通知的实现原理三、代码示例分析1. 设备结构

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构建的现代化图片水印在线工具... 目录概述功能亮点使用方法技术解析延伸思考运行效果项目源码下载总结概述在社交媒体和内容创作日益频繁的