首页 > 编程语言 > NodeJS系列(6)- ECMAScript 6 (ES6) 语法(四)

NodeJS系列(6)- ECMAScript 6 (ES6) 语法(四)

时间:2023-06-29 10:34:15浏览次数:52  
标签:function ES6 resolve console log NodeJS yield Promise ECMAScript


本文在 “NodeJS系列(2)- NPM 项目 Import/Export ES6 模块” 的 npmdemo 项目的基础上,继续介绍并演示 Promise 对象、Generator 函数、async 函数 等 ES6 语法和概念。

NodeJS ES6:https://nodejs.org/en/docs/es6
ECMA:https://www.ecma-international.org/publications-and-standards/standards/ecma-262/

1. Promise 对象

    Promise 是异步编程的一种解决方案:从语法上讲,Promise 是一个对象,从它可以获取异步操作的消息;从语义上讲,它是承诺,承诺它过一段时间会给你一个结果。Promise 有三种状态:pending (等待),fulfiled (成功),rejected (失败);状态一旦改变,就不会再变。Promise 实例创建后 (new 操作后),会立即执行。

    Promise 其实是一个构造函数,有 all、reject、resolve 这几个方法,原型上有 then、catch 等方法。

    使用 Promise 可以避免函数多级回调嵌套,提高代码的可读性,降低代码的维护难度,而且 Promise 可以支持多个并发的请求,获取并发请求中的数据。

    Promise 提供的 “状态” 机制,用维护状态、传递状态的方式来使得回调函数能够及时被调用,比传递 callback 函数要简单、灵活。
    
    示例代码如下:

        let p = new Promise((resolve, reject) => {
            console.log("promise -> start")
            setTimeout(function(){
                let num = Math.random()
                console.log("setTimeout: num = " + num)
                if (num >= 0.5) {
                    // 成功
                    resolve(num)
                } else {
                    // 失败
                    reject('< 0.5')
                }
            }, 2000)
            console.log("promise -> end")
        })

        p.then((data) => {
            // 成功
            console.log('resolve: ' + data)
        }).catch((err) => {
            // 失败
            console.log("reject: " + err)
        })

    输出成功结果:

        promise -> start
        promise -> end
        setTimeout: num = 0.6989372571259511
        resolve: 0.6989372571259511


    输出失败结果:

        promise -> start
        promise -> end
        setTimeout: num = 0.09101305143954774
        reject: < 0.5


    then 方法接收 resolve 返回的数据,catch 方法接收 reject 返回的数据。

    1) then 链式操作  

        有三个任务 task 1、task 2 和 task 3,task 2 必须收到 task 1 的成功结果才能执行,task 3 必须收到 task 2 的成功结果才能执行。

        以下是 then 链式操作的示例代码:

            function task2() {
                let p2 = new Promise(function(resolve, reject){
                    setTimeout(function(){
                        console.log('Task 2 finish')
                        resolve('success_2')
                    }, 1000)
                })
                return p2
            }

            function task3() {
                var p3 = new Promise(function(resolve, reject){
                    setTimeout(function(){
                        console.log('Task 3 finish')
                        resolve('success_3')
                    }, 1000)
                })
                return p3     
            }

            let p1 = new Promise((resolve, reject) => {
                setTimeout(function(){
                    console.log('Task 1 finish')
                    resolve('success_1')
                }, 1000)
            })

            p1.then((data) => {
                console.log(data)
                return task2()
            }).then((data) => {
                console.log(data)
                return task3()
            }).then((data) => {
                console.log(data)
                return 'success_4'
            }).then((data) => {
                console.log(data)
            })


        输出结果:

            Task 1 finish
            success_1
            Task 2 finish
            success_2
            Task 3 finish
            success_3
            success_4


        示例代码中 p1.then 和第 2 个 then 依次返回 p2 和 p3 两个 Promise 对象,即第 2 个 then 绑定在 p2 上,第 3 个 then 绑定在 p3 上。
        
        第 3 个 then 返回的是字符串(不是 Promise 对象),所以第 4 个 then 没有绑定 Promise 对象,直接接收第 3 个 then 的返回数据。
 
    2) all 方法

        all 方法是与 then 同级的并行执行异步操作的方法。all 方法是在所有异步操作执行完后,并且执行结果都是成功的时候才执行回调。

        以下是 all 方法的示例代码:

            function task1() {
                let p1 = new Promise(function(resolve, reject){
                    setTimeout(function(){
                        console.log('Task 1')
                        resolve('success_1')
                    }, 1000)
                })
                return p1
            }

            function task2() {
                let p2 = new Promise(function(resolve, reject){
                    setTimeout(function(){
                        console.log('Task 2')
                        resolve('success_2')
                    }, 1000)
                })
                return p2
            }

            function task3() {
                var p3 = new Promise(function(resolve, reject){
                    setTimeout(function(){
                        console.log('Task 3')
                        resolve('success_3')
                        //reject('error_3')
                    }, 1000)
                })
                return p3     
            }

            console.log('Promise.all() ...')
            Promise.all([task1(), task2(), task3()])
                    .then((data) => {
                        console.log(data)
                    }).catch((err) => {
                        console.log(err)
                    })


        输出结果:

            Promise.all() ...
            Task 1
            Task 2
            Task 3
            [ 'success_1', 'success_2', 'success_3' ]


        以上 task1()、 task2() 和 task3() 函数都是调用 resovle 返回成功,满足 all 方法的条件,执行 then 方法 。
        
        修改 task3() 函数,注释掉 resolve('success_3') 行,去掉 //reject('error_3') 行的注释符,运行后 task3() 调用 reject 返回失败,不满足 all 方法的条件,执行 catch 方法。  

    3) race 方法

        race 方法是与 then 同级的并行执行异步操作的方法。race 方法是不管执行完成的状态是成功或失败,先执行完成的方法就先执行回调,其它方法的执行结果都被忽略。

        以下是 race 方法的示例代码:

            function task1() {
                let p1 = new Promise(function(resolve, reject){
                    setTimeout(function(){
                        console.log('Task 1')
                        resolve('success_1')
                    }, 5000)
                })
                return p1
            }

            function task2() {
                let p2 = new Promise(function(resolve, reject){
                    setTimeout(function(){
                        console.log('Task 2')
                        resolve('success_2')
                    }, 3000)
                })
                return p2
            }

            function task3() {
                var p3 = new Promise(function(resolve, reject){
                    setTimeout(function(){
                        console.log('Task 3')
                        resolve('success_3')
                        //reject('error_3')
                    }, 1000)
                })
                return p3     
            }

            console.log('Promise.race() ...')
            Promise.race([task1(), task2(), task3()])
                    .then((data) => {
                        console.log(data)
                    }).catch((err) => {
                        console.log(err)
                    })

        输出结果:

            Promise.race() ...
            Task 3
            success_3
            Task 2
            Task 1


        以上 task3() 最先调用 resovle 返回成功,满足 race 方法的条件,执行 then 方法。task1() 和  task2() 继续执行,但是执行结果被忽略,即它们俩没有执行 then 方法。
        
        修改 task3() 函数,注释掉 resolve('success_3') 行,去掉 //reject('error_3') 行的注释符,运行后 task3() 最先调用 reject 返回失败,也满足 race 方法成功返回的条件,执行 then 方法。  


2. Generator 函数

    Generator 函数是 ES6 提供的一种异步编程解决方案,语法行为与传统函数完全不同,执行 Generator 函数会返回一个遍历器对象,可以依次遍历 Generator 函数内部的每一个状态。

    Generator 函数语法格式:
    
        function* f() {
            yield ...
        }

        注:* 用来表示函数为 Generator 函数,yield 用来定义函数内部的状态。
    
    示例

        function* test() {
            yield 1
            yield 2
            return 3
        }

        let t = test()   // 创建遍历器(或迭代器)
        let r = t.next()

        while(!r.done) {
            console.log(r)
            r = t.next()

        }

        console.log(r)

    输出结果:

        { value: 1, done: false }
        { value: 2, done: false }
        { value: 3, done: true }

    遍历器调用 next() 方法,遇到 yield 停止执行并返回对象 { value: 1, done: false },done 的值为 true 时,表示遍历已经结束。
    
    1) next() 方法的参数

        next() 方法返回一个对象,yield 语句本身是没有返回值,或者说返回 undefined。next() 方法可以带一个参数,该参数就会被当作上一个 yield 语句的返回值。

        示例

            function* gen() {
                for (let i=0; true; i++) {
                    console.log('yield ' + i);
                    let y = yield i;
                    console.log('y = ' + y);
                    
                    if (y) {
                        return i+1;
                    }
                }
            }

            var g = gen();
            console.log(g.next())
            console.log(g.next())
            console.log(g.next(true))


        输出结果:

            yield 0
            { value: 0, done: false }
            y = undefined
            yield 1
            { value: 1, done: false }
            y = true
            { value: 2, done: true }


        通过 next() 方法的参数,可以在 Generator 函数运行的不同阶段,从外部向内部注入不同的值,从而调整函数行为。

        由于 next() 方法的参数表示上一个 yield 语句的返回值,所以第一次使用 next() 方法时,不能带有参数,V8 引擎直接忽略第一次使用 next() 方法时的参数。

    2) for ... of 遍历

        for ... of 循环可以遍历 Generator 函数,不再需要调用 next() 方法,遍历到返回对象的 done 属性为 true,循环就会中止,且不包含该返回对象。

        示例

            function* f() {
                yield 1;
                yield 2;
                yield 3;
                return 4;
            }

            for (let i of f()) {
                console.log(i);
            }

        输出结果:

            1
            2
            3
    
    3) yield* 语句

        如果 yield 命令后面是一个遍历器,需要在 yield 命令后面加上星号,表明它返回的是一个遍历器,即 yield* 语句的返回值。

        示例

           let a = (function* () {
                yield 'Hello';
                yield 'Bye';
            } ());

            let b = (function* () {
                yield 'Good';
                yield* a;
                yield 'OK';
            } ());

            for (let i of b) {i
                console.log(i);
            }


        输出结果:

            Good
            Hello
            Bye
            OK


        如果 yield* 语句后面是可遍历(或可迭代)类型的数据(比如:数组),表明它返回的是这个可遍历数据的遍历器。

        示例

            // 遍历数组
            function* arr(){
                yield* ["a", "b"];
            }
            
            for (let i of arr()) {
                console.log(i);
            }

            console.log('-------------------------')

            // 遍历嵌套数组
            function* iterArr(marr) {
                if (Array.isArray(marr)) {
                    for(let i=0; i < marr.length; i++) {
                        yield* iterArr(marr[i]);
                    }
                } else {
                    yield marr;
                }
            }

            const marr = [ 1, [2, 3], 4 ];
            for(let i of iterArr(marr)) {
                console.log(i);
            }


        输出结果:

            a
            b
            -------------------------
            1
            2
            3
            4



3. async 函数

    async/await 是 ES7 才有的与异步操作有关的关键字,和 Promise,Generator 有很大关联的。

    async 函数是 Generator 函数的改进版,在写法上比较相似。通过 await 操作符可以让异步操作等待,直至执行完毕为止。同时 await 还会对等待的代码进行检测,如果不是异步,将不会执行等待。
    
    示例

        function task1(msg) {
            let p = new Promise(function(resolve, reject){
                setTimeout(function(){
                    resolve(msg)
                }, 2000)
            })
            return p
        }

        function task2(msg) {
            let p = new Promise(function(resolve, reject){
                setTimeout(function(){
                    reject('error_2')
                }, 2000)
            })
            return p
        }

        async function main() {

            try {

                console.log("Start 1")
                let ret1 = await task1('task 1')
                console.log("await ret1: " + ret1)

                console.log("Start 2 ")
                let ret2 = await task2('task 2')
                console.log("await ret2: " + ret2)

            } catch (err) {
                console.log(err)
            }
        }

        main()


    输出结果:

        Start 1
        await ret1: task 1
        Start 2
        error_2


    以上输出结果可以看出,加 await 就可以实现异步操作同步化,而且要增加某种判断。所以 async/await 相对于 Generator 函数显得简单很多。


标签:function,ES6,resolve,console,log,NodeJS,yield,Promise,ECMAScript
From: https://www.cnblogs.com/tkuang/p/17513383.html

相关文章

  • NodeJS系列(5)- ECMAScript 6 (ES6) 语法(三)
    在“NodeJS系列(3)-ECMAScript6(ES6)语法(一)”和“NodeJS系列(4)-ECMAScript6(ES6)语法(二)”里,我们介绍并演示let、const、Symbol、函数扩展、类等ES6语法和概念。本文在“NodeJS系列(2)-NPM项目Import/ExportES6模块”的npmdemo项目的基础上,继续介绍并演示Ref......
  • nodeJS常用路径API示例简记
    常用API汇总:process.cwd():返回当前执行node命令时的所在目录path.dirname():返回当前执行文件的所在目录__dirname:返回当前执行文件的所在目录(只能在CommonJS规范下使用)__filename:返回当前执行文件的绝对路径(只能在CommonJS规范下使用......
  • NodeJS系列(4)- ECMAScript 6 (ES6) 语法(二)
    在“NodeJS系列(3)-ECMAScript6(ES6)语法(一)”里,我们介绍并演示let、const、Symbol等ES6语法和概念。本文在“NodeJS系列(2)-NPM项目Import/ExportES6模块”的npmdemo 项目的基础上,继续介绍并演示函数扩展、类等ES6语法和概念。NodeJSES6:https://nodejs.org......
  • NodeJS本地环境安装及设置
    背景作为一个后端,服务接口自然不在话下。分分钟给安装上百个接口。但是交互。。。postman,postman,,,,,可视化和交互上那简直真的就是都长这样:想搞个React前端页面。先使用一下单表的增删改查操作。用来操作数据库玩玩一、概念1、Node.js是什么?Node.js是一个开源和跨......
  • Nodejs介绍与安装
    Nodejs介绍与安装介绍Nodejs是一个能够在服务器端运行JavaScript的开放源代码、跨平台JavaScript运行环境Nodejs采用Google开发的V8引擎运行js代码,使用事件驱动、非阻塞和异步I/O模型等技术来提高性能,可优化应用程序的传输量和规模Nodejs大部分基本模块都用JavaScript编写。......
  • typescript之ECMAScript5、ES6
    1、基础常识1.1简介ECMAScript(/ekma/,简称ES)是javascript的标准化规范,其实javascript是ECMAScript的扩展语言。ES定义了一些标准的语法,JS对其进行了DOM、BOM扩展。1.2ES迭代史ES6(又叫ES2015)是ECMA协会在2015年6月发行的一个版本,因为是ECMAScript的第6个版本,所以也称为ES......
  • ES6 模块化组件暴露方式
    分别<script>//分别exportconstschool=Vue.extend({data:{},methods:{}})</script> 统一<script>constschool=Vue.extend({data:{},......
  • ES5和ES6的继承
    (1)ES5//构造函数functionPerson(name){this.name=name}//原型Person.prototype.say=function(){console.log('我是'+this.name)}//子类构造函数继承父类构造函数functionSon(name,age){//调用父类构造函数,让父类中的this指向当前子类Person.call(thi......
  • find-my-way nodejs 快速的http 路由框架
    find-my-way基于了radixtree开发的路由框架,支持路由参数,通配符,同时语言无关fastify以及restify都使用了路由框架,同时也受echo启发说明了解find-my-way的使用以及内部机制对于学习fastify是比较有用的,fastify不少有意思的插件机制都利用了find-my-way参考资料https://g......
  • NodeJS系列(3)- ECMAScript 6 (ES6) 语法(一)
    ECMAScript6(ES6)是最新的JavaScript语言的标准化规范,它的目标是使JavaScript语言可以用来编写复杂的大型应用程序,成为企业级开发语言。本文在“NodeJS系列(2)-在NPM项目里使用ECMAScript6(ES6)规范”的npmdemo的基础上,介绍并演示let、const、Symbol等ES6语法......