关于前端:Deno从入门到实践

31次阅读

共计 6931 个字符,预计需要花费 18 分钟才能阅读完成。

DenoRyan Dahl2017年创建的,此外
Ryan Dahl 也是 Node.js 的创始人,从 2007 年始终到 2012 年,他起初把 Node.js 移交给了其余开发者,不再过问了,转而钻研人工智能。
他始终不是很喜爱 Python 语言,长此以往,就想搞一个 JavaScript 语言的人工智能开发框架。等到他再回过头捡起 Node.js,发现这个我的项目曾经背离了他的初衷,有一些无奈漠视的问题,从此 deno 从此应运而生。
上面咱们来看看 Deno 的根本应用,并用它构建一个简略的聊天网站。

装置 Deno

有很多种形式装置 Deno,具体如何装置可参考这篇文章 deno 装置。
我应用 Homebrew 装置 Deno(感觉这种形式要快一点)

brew install deno
deno 1.4.6
v8 8.7.220.3
typescript 4.0.3

能够看到的是 deno 依赖中不存在 npmnpmnode的包管理工具。deno舍弃了 npm 应用了另外的形式进行包的治理。

Hello world

理解一门语言,国际惯例,先上 Hello World
首先创立一个文件,这个文件能够是 js 文件也能够是 ts 文件,Deno内置对 ts 的反对,不须要应用 typescriptts文件在进行编译一遍 (因为作者对ts 不怎么相熟,所以文章应用 js 进行编写)。运行这个文件调用 deno run [file]
上面是实例代码

// example.js
console.log("Hello World")

执行deno run example.js,上面是打印后果

deno run example.js
Hello world

如果咱们应用 ts 格局,能够本人定义 tsconfig.json 文件,而后应用 deno run -c tsconfig.json example.ts 来笼罩 deno 内置的 ts 配置,deno 外部的默认配置可参考 Using Typescript

创立 http 服务

node中应用 import path from 'path' 的形式引入库或者工具,deno因为没有 npm 的概念,如果须要引入某个库,间接从 url 中获取须要的工具就能够,这样做的是为了尽可能的缩小包文件的体积。
例如创立一个 http server 咱们须要应用 denohttp服务: https://deno.land/std/http/deno所有的规范库都在 https://deno.land/std
首先创立两个文件,一个用服务端代码,一个客户端代码: server.jsstatic/index.html
上面是 index.html 的内容

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta charset="utf-8" />
    <title>Example using Deno</title>
  </head>
  <body>index.html</body>
</html>

server.js

import {listenAndServe} from 'https://deno.land/std/http/server.ts';
const file_url = fromFileUrl(new URL('../static/index.html', import.meta.url));
listenAndServe(
  {port: 3000,},
  async req => {if (req.method === 'GET' && req.url === '/') {
      req.respond({
        status: 200,
        headers: new Headers({'content-type': 'text/html',}),
        body: await Deno.readTextFile(file_url),
      });
    }
  }
);

console.log('Server running on localhost:3000');

deno 中能够应用 ESModules 的模块形式代替 Common.js。须要留神的是在引入文件的时候必须要加上文件后缀名,例如引入文件a,必须写a.js。此外,绝对于node`deno 默认反对 async-await`。
当咱们运行 deno run server.js,能够看到和先前的Hello World 例子有两个中央差别.

  1. 应用 http 的形式引入依赖,而不是 npm 或者 yarn 的形式。在执行文件之前,deno会首先下载所有的依赖放入缓存,当咱们不清空缓存的时候能够尝试 --reload 命令
  2. 执行的时候会抛出两个谬误,一个是没有权限接入网络 Uncaught PermissionDenied: network access to "0.0.0.0:3000", 这个能够增加--allow-net 示意运行网络拜访,在拜访 localhost:3000deno 抛出谬误 Uncaught PermissionDenied: read access to 无奈读取文件。这里也是和 node 有差别的中央,大多数状况下 node 能够不须要用户的批准获取网络文件等权限。deno基于平安思考限度了大量的权限,如果须要读取某个文件夹的内容须要应用deno --allow-read= 文件目录。更多命令可参考deno run -h

执行上面命令就能够启动 http 服务,并且拜访到 index.html 的内容

deno run --allow-net --allow-read server.js
Server running on localhost:3000

创立聊天利用

上面来创立一个简略的聊天利用,次要实现的性能:

  1. 客户端 1 发送音讯
  2. 服务端收到音讯后,被动推送音讯给客户端 2
  3. 客户端 2 立即收到音讯并显示

上面是服务端代码的具体实现,首先创立一个 chat.js, 这个文件次要是用于存储websocket 实例,承受客户端发送的音讯,被动向客户端发送音讯,上面是具体实现:

import {isWebSocketCloseEvent} from 'https://deno.land/std/ws/mod.ts';
import {v4} from 'https://deno.land/std/uuid/mod.ts';

const users = new Map();

function broadcast(message, senderId) {if (!message) {return false;}
  users.forEach(user => {user.send(senderId ? `[${senderId}]: ${message}` : message);
  });
}

export async function chat(ws) {const userId = v4.generate();

  users.set(userId, ws);
  broadcast(`> User with the id ${userId} is connected`);
  for await (const event of ws) {
    const message = typeof event === 'string' ? event : '';

    broadcast(message, userId);

    if (!message && isWebSocketCloseEvent(event)) {users.delete(userId);
      broadcast(`> User with the id ${userId} is disconnected`);
      break;
    }
  }
}

而后在 server.js 中定义路由,用于解决 websocket 申请

import {listenAndServe} from "https://deno.land/std/http/server.ts";
import {acceptWebSocket, acceptable} from "https://deno.land/std/ws/mod.ts";
import {chat} from "./chat.js";

listenAndServe({port: 3000}, async (req) => {if (req.method === "GET" && req.url === "/") {
    req.respond({
      status: 200,
      headers: new Headers({"content-type": "text/html",}),
      body: await Deno.open("./index.html"),
    });
  }

  // WebSockets Chat
  if (req.method === "GET" && req.url === "/ws") {if (acceptable(req)) {
      acceptWebSocket({
        conn: req.conn,
        bufReader: req.r,
        bufWriter: req.w,
        headers: req.headers,
      }).then(chat);
    }
  }
});

console.log("Server running on localhost:3000");

上面是客户端的代码,这里为了简略实用 preact,他不须要额定的babelwebpack 配置实用十分的不便。

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Example using Demo</title>
</head>
<body>
  <div id="app"></div>
  <script type="module">
    import {html, render, useEffect, useState} from 'https://unpkg.com/htm/preact/standalone.module.js';

    let ws;

    function Chat() {const [messages, setMessages] = useState([]);
      const onReceiveMessage = ({data}) => setMessages(m => [...m, data]);
      const onSendMessage = e => {const msg = e.target[0].value;

        e.preventDefault();
        console.log(msg);
        ws.send(msg);
        e.target[0].value = '';
      };

      useEffect(() => {if (ws) {ws.close();
        }
        ws = new WebSocket(`ws://${window.location.host}/ws`);
        ws.addEventListener('message', onReceiveMessage);
        return () => {ws.removeEventListener('message', onReceiveMessage);
        };
      }, []);
      return html`
        ${messages.map(message => html` <div>${message}</div> `)}

        <form onSubmit=${onSendMessage}>
          <input type="text" />
          <button>Send</button>
        </form>
      `;
    }
    render(html`<${Chat} />`, document.getElementById('app'));

  </script>
</body>
</html>

第三方库的治理

下面例子中次要实用了 deno 的规范库,上面是 deno 的第三方库的应用,引入第三方库也是通过 url 的形式来引入。官网次要蕴含了规范库和第三方库,上面是具体的地址

  • 规范库: https://deno.land/std/
  • 第三方库: https://deno.land/x/

然而,官网上的第三放库切实是太少了不能满足咱们的需要。好消息是咱们能够应用 https://www.pika.dev 下面的库,此外能够通过打包工具如 Parcelnode包转换成 deno 可能应用的包。
上面借助 camel-case 将用户输出的输出内容转为驼峰式,增加以下代码到 chat.js

import {camelCase} from 'https://cdn.pika.dev/camel-case@^4.1.1';
// ...before code
const message = camelCase(typeof event === 'string' ? event : '')
// ... before code

从新运行一次,能够看到更改的内容曾经失效了。

然而下面这种形式存在一个问题,如果多个文件都依赖了 camelCase,每个文件须要申明一个url。当降级camel-case 的时候,须要把所有依赖以后库的版本号都更改一下,很可能漏掉呈现一些问题。所以举荐对于引入的第三方库能够在一个文件中进行治理,如下:

//deps.js
export {camelCase} from 'https://cdn.pika.dev/camel-case@^4.1.1';
// chat.js
import {camelCase} from './deps.ts';

编写测试

Deno绝对于 node 内置了十分多的性能,例如主动生成文档,代码格式化,自动测试等等。
例如当初创立一个函数用于统计字符串中一个有多少个大写字母

/**
 * 统计字符串的大写字母的个数
 */
export function camelize(text) {// todo:}

执行上面命令deno doc camelize,就能够生成以后函数的文档

deno doc camelize
function camelize(text)
  统计字符串的大写字母的个数

而后创立一个测试文件 test.js,用于测试以后函数是否符合要求。
Deno 内置了一些测试的工具如 Deno.test,断言等等,上面是test.js 的内容

import {assertStrictEq} from "https://deno.land/std/testing/asserts.ts";
import {camelize} from "./camelize.js";

Deno.test("camelize works", async () => {assertStrictEq(camelize("AAbbCC"), 4);
});

而后执行 deno test 发现有以下报错

running 1 tests
test camelize works ... FAILED (2ms)

failures:

camelize works
AssertionError: Values are not strictly equal:


    [Diff] Actual / Expected


-   undefined
+   4

    at assertStrictEquals (asserts.ts:298:9)
    at file:///Users/bytedance/cornelius/deno-chart/test.js:5:3
    at asyncOpSanitizer (deno:cli/rt/40_testing.js:34:13)
    at Object.resourceSanitizer [as fn] (deno:cli/rt/40_testing.js:68:13)
    at TestRunner.[Symbol.asyncIterator] (deno:cli/rt/40_testing.js:240:24)
    at AsyncGenerator.next (<anonymous>)
    at Object.runTests (deno:cli/rt/40_testing.js:317:22)

failures:

        camelize works

test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out (2ms)

能够看到咱们的测试是没有通过的,上面更改 camelize 中的代码

export function camelize(text) {return (text.match(/[A-Z]/g) || []).length;
}

再次执行deno test,能够看到通过了测试

running 1 tests
test camelize works ... ok (4ms)

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out (4ms)

Debugging

除了 console,借助chrome 还可能进行断点调试。

  1. 首先在启动命令中增加 --inspect-brk 例如 deno run --inspect-brk camelize.js 执行后会在 9229 端口启动一个websocket
  2. chrome://inspect 中增加一个端口如: localhost:9229
  3. 点击 inspect 就能够调试 deno 代码了
  4. 调试代码就和失常的调试一样就能够了

欢送关注「前端好好学」,前端学习不迷路或加微信 ssdwbobo,一起交流学习

正文完
 0