zoukankan      html  css  js  c++  java
  • koa2教程(一)-快速开始

    来自Koa官网对于Koa的简介:

    koa 是由 Express 原班人马打造的,致力于成为一个更小、更富有表现力、更健壮的 Web 框架。 使用 koa 编写 web 应用,通过组合不同的 async函数,可以免除重复繁琐的回调函数嵌套, 并极大地提升错误处理的效率。koa 不在内核方法中绑定任何中间件, 它仅仅提供了一个轻量优雅的函数库,使得编写 Web 应用变得得心应手。

    简而言之Koa就是基于NodeJs的Web开发框架

    Koa2相较Koa1最大的区别就是中间件的写法不同,Koa1使用Generator,Koa2使用async/await语法。由于Koa2使用async/await语法,所以在学习之前,请使用v7.6.0+的Node

    Koa2快速开始

    安装Koa2

    npm init
    npm install koa
    

    一个简单的Hello World程序开场,

    //index.js
    const Koa = require('koa')
    const app = new Koa()
    
    app.use( async ctx  => {
      ctx.body = 'Hello World'
    })
    
    app.listen(3000,()=>{
      console.log("server is running at 3000 port");
    })
    

    启动demo

    node index.js
    

    访问http://localhost:3000,页面如下所示

    页面

    使用Async/Await语法

    在讲解Async/Await之前,有必要简单讲一下javascript的异步发展历程,并给每种异步的方式给一段示例代码

    异步主要经历了这么几个过程:

    Es6之前:

    • 回调函数(callback)

    Es6

    • Promise对象
    • Generator函数

    Es7

    • async/await语法
    使用async/await
    • async用于声明一个function是异步的
    • await只能出现在用async修饰的function中
    async到底起什么作用
    async function test(){
        return "Hello World";
    }
    
    var result=test();
    console.log(result);
    //打印Promise { 'Hello World' }
    

    async函数返回一个promise对象,如果在async函数中返回一个直接量,async会通过Promise.resolve封装成Promise对象。

    我们可以通过调用promise对象的then方法,获取这个直接量。

    test().then(data=>{
        console.log(data);
    })
    //打印 "Hello World"
    

    那如过async函数不返回值,又会是怎么样呢?

    //不返回值
    async function test(){
       
    }
    var result=test();
    console.log(result);
    //打印Promise { undefined }
    
    await到底在等什么

    await会暂停当前async的执行,await会阻塞代码的执行,直到await后的表达式处理完成,代码才能继续往下执行。

    await后的表达式既可以是一个Promise对象,也可以是任何要等待的值。

    如果await等到的是一个 Promise 对象,await 就忙起来了,它会阻塞后面的代码,等着 Promise 对象 resolve,然后得到 resolve 的值,作为 await 表达式的运算结果。

    上边你看到阻塞一词,不要惊慌,async/await只是一种语法糖,代码执行与多个callback嵌套调用没有区别,本质并不是同步代码,它只是让你思考代码逻辑的时候能够以同步的思维去思考,避开回调地狱,简而言之-async/await是以同步的思维去写异步的代码,所以async/await并不会影响node的并发数,大家可以大胆的应用到项目中去!

    如果它等到的不是一个 Promise 对象,那 await 表达式的运算结果就是它等到的东西。

    举个例子

    function A() {
        return "Hello ";
    }
    
    async function B(){
        return "World";
    }
    
    async function C(){
        //等待一个字符串
        var s1=await A();
      	//等待一个promise对象,await的返回值是promise对象resolve的值,也就是"World"
        var s2=await B();
        console.log(s1+s2);
    }
    
    C();
    //打印"Hello World"
    

    华丽的分割线,async/await讲完了,如果大家对别的异步方式感兴趣的话,可以继续往下看,不感兴趣,到此为止啊!


    回调函数(callback)

    回调函数就是一个参数,将这个函数作为参数传到另一个函数里面,当那个函数执行完之后,再执行传进去的这个函数。这个过程就叫做回调,回调其实按字面意思也很好理解,先处理主函数,回头再调用作为参数传进来的这个参数,举个栗子。

    function A(callback){
        console.log("我是主函数");
        callback();
    }
    
    function B(){
        console.log("我是回调函数");
    }
    
    A(B);
    //输出结果
    我是主函数
    我是回调函数
    
    Promise对象

    **Promise **对象用于一个异步操作的最终完成(或失败)及其结果值的表示。(简单点说就是处理异步请求。我们经常会做些承诺,如果我赢了你就嫁给我,如果输了我就嫁给你之类的诺言。这就是promise的中文含义:诺言,一个成功,一个失败。)

    ​ ---MDN对Promise的解释

    例子:使用Promise封装fs模块中的readFile()方法

    创建一个Promise对象

    ​ Promise构造函数的参数是一个函数,我们把它称为处理器函数,处理器函数接收两个函数reslovereject作为其参数,当异步操作顺利执行则执行reslove函数, 当异步操作中发生异常时,则执行reject函数。通过resolve传入得的值,可以在then方法中获取到,通过reject传入的值可以在chatch方法中获取到,

    ​ 因为thencatch都返回一个相同的promise对象,所以可以进行链式调用。

    const fs=require("fs");
    
    //path参数是文件的路径,返回一个Promise对象
    function readFileByPromise(path){
      	//显示返回一个Promise对象
        return new Promise((resolve,reject)=>{
            fs.readFile(path,"utf8",function(err,data){
                if(err)
                    reject(err);
                else
                    resolve(data);
            })
        })
    }
    
    readFileByPromise("a.txt").then( data =>{
      	//打印文件中的内容
        console.log(data);
    }).catch( error =>{
      	//抛出异常,
        console.log(error);
    })
    
    Generator函数

    Generator是 ES6 的新特性,中文译为生成器,在以前一个函数中的代码要么被调用,要么不被调用,还不存在能暂停的情况,Gnenerator让代码暂停成为可能,定义一个生成器很简单,在函数名前加个*****号,使用上也与普通函数有区别,看下面的例子。

    一个简单的例子

    1、定义生成器函数

    function *Calculate(a,b){
      let sum=a+b;
      console.log(sum);
      let sub=a-b;
      console.log(sub);
    }
    
    

    2、创建Generator对象

    Generator函数不能直接调用,直接调用Generator函数会返回一个Generator对象,只有调用Generator对象的next()方法才能执行函数里的代码。

    let gen=Calculate(2,7);
    

    3、执行Generator函数代码

    gen.next();
    //打印
    //9
    //-5
    
    yield关键字

    其实单独介绍Generator并没有太大的价值,要配合yield关键字,才能真正发挥Generator的价值。yield能将生Generator函数的代码逻辑分割成多个部分,下面改写上面的生成器函数。

    function *Calculate(a,b){
      let sum=a+b;
      yield console.log(sum);
      let sub=a-b;
      yield console.log(sub);
    }
    let gen=Calculate(2,7);
    gen.next();
    //输出
    //9
    

    可以看到这段代码执行到第一个yield处就停止了,如果要让里边所有的代码都执行完就得反复调用next()方法

    let gen=Calculate(2,7);
    //因为上边代码我用了两个yield,所以调用了两次next()
    gen.next();
    gen.next();
    //输出
    //9
    //-5
    
    Generator与异步编程

    实现一个功能,先读取a.txt,再读取b.txt,必须按顺序读取。

    const fs=require("fs");
    
    fs.readFile("a.txt",(err,data)=>{
        if(!err){
            console.log(data);
            fs.readFile("b.txt",(err,data)=>{
                if(!err)
                    console.log(data);
            })
        }
    })
    

    这是一个典型的回调嵌套,过多的回调嵌套造成代码的可读性和可维护性大大降低,形成了令人深恶痛绝的回调地狱,试想如果有一天让你按顺序读取10个文件,那就得嵌套10层,再或者需求变更,读取顺序要变了先读b.txt,再度a.txt那改来真的不要太爽。

    使用Generator改写上面的代码

    Generator函数的强大在于允许你通过一些实现细节来将异步过程隐藏起来,依然使代码保持一个单线程、同步语法的代码风格。这样的语法使得我们能够很自然的方式表达我们程序的步骤/语句流程,而不需要同时去操作一些异步的语法格式

    const fs=require("fs");
    
    function readFile(path) {
        fs.readFile(path,"utf8",function(err,data){
              it.next(data);
        })
    }
    
    function *main() {
        var result1 = yield readFile("a.txt");
        console.log(result1);
    
        var result2 = yield readFile("b.txt");
        console.log(result2);
    
        var result3 = yield readFile("c.txt");
        console.log(result3);
    }
    
    var it = main();
    it.next(); 
    
  • 相关阅读:
    C语言使用正则表达式
    linux 有名管道(FIFO)
    sendto() 向广播地址发包返回errno 13, Permission denied错误
    NSUserDefaults(数据存储)
    iOS开发UI篇—UIScrollView控件实现图片缩放功能
    李洪强iOS开发之-环信02_iOS SDK 介绍及导入
    李洪强iOS开发之-环信01_iOS SDK 前的准备工作
    iOS开发UI篇—UIScrollView控件介绍
    iOS开发UI篇—iOS开发中三种简单的动画设置
    iOS开发UI篇—IOS开发中Xcode的一些使用技巧
  • 原文地址:https://www.cnblogs.com/houhanbin121456/p/8297472.html
Copyright © 2011-2022 走看看