Quantcast
Channel: CNode:Node.js专业中文社区
Viewing all 14821 articles
Browse latest View live

Node.js技术栈—侧重于服务端的学习指南

$
0
0

Node.js技术栈

本文档是作者从事Node.js Developer以来的学习历程,旨在为大家提供一个较详细的学习教程,侧重点更倾向于Node.js服务端所涉及的技术栈,如果本文能为您得到帮助,请给予支持!

如何支持:

  • 搜索公众号 Node.js技术栈进行关注
  • 点击右上角Star :star: 给予关注
  • 分享给您身边更多的小伙伴

Githubhttps://github.com/Q-Angelo/Nodejs-Roadmap

JavaScriptECMAScript6Node.jsDataBaseMicroserviceHTTPDevOps工具资料

JavaScript

ECMAScript6

Nodejs

DataBase

Microservice

HTTP协议实战

DevOps

工具

资料

为Node.js学习贡献一份自己微小的力量,未完待续,持续更新中。。。


把代码写烂是种技术,前几天在项目里看到的一段代码让我非常震惊,感叹自己打码多年仍然追赶不上大神的脚步

$
0
0

QQ图片20190505144920.png所调用的两个函数在整个项目中只有那两行代码调用了,大神能把烂代码写得如此优雅简直让我刮目相看 值得庆幸的是,大神离职前把所有数据库表的每个字段都写上了注释,非常赞

新人求助 url.parse( ).path 无法使用

$
0
0

想用nodejs实现数据接收并推送到网页,但 url.parse( ).path却无法使用。请各位大佬帮帮萌新。 代码如下(数据接收部分省略)

var http = require('http');
var fs   = require('fs');
var url_parser = require('url');
var querystring = require('querystring');
var man = 0;
var car = 0;

var server=http.createServer(function(req,res)
{
    var post = '';
    var raw_url = req.url;
    var url = url_parser.parse(raw_url,true);
    var pathname = url.pathname;
    var path = url.path;          //**url.path无法使用**
	
    //响应OneNet发来的请求,接收数据
    if(pathname == '/dataPort')
    {
	           //已省略
    }
//
    if(path == '/index')
    {
        res.writeHead(200,{'Content-Type':'text/html'});
        fs.readFile('./index.html','utf-8',function(err,data)
        {
            res.write(data);
            res.end();
        });
    }
    //响应'/?test=ajax'
    else if(path == '/?test=ajax')
    {
        console.log('start ajax');
        res.writeHead(200,{'Content-Type':'text/plain','Access-Control-Allow-Origin':'*'});
        var jlatitude_json = {"man":man,"car":car};
        var str = JSON.stringify(jlatitude_json);
        res.write(str);
        res.end();
    }
});

server.listen(80);
console.log('server running at port 80');   

 code \n``` 
html  ajax部分代码
```js\n    
<script type="javascript">
    //更新数据
    var car=0;
    var man=0;
    //发送ajax请求
    function start(){
        $.ajax({
            url:'http://47.102.122.37:80/',
            dataType:'json',
            type:'get',
            data:{test:'ajax'},
            success:function(data)
            {
                function UpdateMAC(data)
                {
                    car = data.car;
                    man = data.man;
                    document.getElementById('man').value = man;
                    document.getElementById('car').value = car;
                }	//更新

            }
        })
    }

    /*
     每隔1秒发送一次经纬度数据请求
     */
    setInterval(function()
    {
        start();
    },3000);
</script>
  code \n```

怎么获取视频里面的某一帧或者某几帧

$
0
0

需求是这样的:用户在上传视频时,上传完成之后,会选择某一帧的图片作为视频的预览图片,也即video标签的poster的值,怎么读取视频里面的帧呢?

这个评论回复的功能是怎么实现的呢

$
0
0

最近也想实现一下这个回复的功能,完全没有思路,还有查看未读消息的功能, 求小伙伴们教教我

nodejs代码加密

$
0
0

网上nodejs的加密基本上都是做成一个可执行文件,但是很多时候的需求是加密部分代码,而不是全部代码。我的思路是写一个解密的文件打包进node里面,可以参考nodejs教程https://github.com/nodejs/node/blob/master/BUILDING.md,如下 image.png

  1. 具体做法是我们自己创建一个文件类型jsxx,此文件放加密的代码。
Module._extensions[".jsxx"] = function(module, filename) {
	// 解密代码	
	// 禁用一些方法,比如说toString等
};
  1. 在启动主文件里面引用当前的模块既可,只有使用相对应的node才行正常启动。
require("jsxx");

typescript依赖注入实践

$
0
0

之前写过的一篇关于《前端IOC的简单实践》,基于本人是一个前端,设计模式的基础知识都不完备,所以内容不是太严谨,正在学习中! 文章中提到了一个关键词:依赖注入。

有小伙伴跟我提说在真实项目中如何使用的,我知道 angular就是借鉴 springioc,奈何我没有用过,下面呢就来说说我之前在nodejs项目上的一些实践。

去年,我贴了一个 nodejs的简易web框架-- lenneth,基于 koa2搞的,简单说就是用装饰器模仿 spring来写 nodejs的注解(说注解习惯了,就不说装饰器了),看下示例:

import {
  Controller,
  Autowired,
  Post,
  Get,
  RequestBody,
  PathVariable,
  Response,
  TResponse,
  UseBefore,
  Description
} from "lenneth";
import { UserService } from "../services";
import { IUserInfo } from "../interface";
import { UserAuth, RuleAuth } from "../middleware";

@Controller("/user")
export class UserController {
  @Autowired()
  userService: UserService;

  @Post("/add")
  @Description("添加会员")
  @UseBefore(UserAuth, RuleAuth)
  async addUser(
    @RequestBody() user: IUserInfo,
    @Response() response: TResponse
  ) {
    response.body = this.userService.addUser(user);
  }

  @Get("/detail/:userId")
  @UseBefore(UserAuth)
  @Description("查询会员")
  async getUser(
    @PathVariable("userId") userId: string,
    @Response() response: TResponse
  ) {
    response.body = this.userService.getUserInfo(userId);
  }
}

看到这些注解,是不是很眼熟,就是从 spring抄来的,具体介绍可以去项目里看看,下面来重点介绍实现 Autowired注解的过程,也就是依赖注入的实践。

看上面的实例,这个项目依赖了一个 UserService类,在这个 UserController这个方法中会用到这个依赖类的某个方法。

依赖注入:

@Autowired()
userService: UserService;

使用:

this.userService.addUser(user);

来看下 Autowired注解的实现:

import { Metadata } from "@common";
import { descriptorOf, getClassName } from "@utils";

/**
 * 注入service,类属性修饰器
 * @param params 实例化参数
 */
export const Autowired = (params: any = ""): Function => {
  return (target: any, propertyKey: string) => {
    // 获取该属性的类型
    let typeClass = Metadata.getType(target, propertyKey);
    const descriptor = descriptorOf(target, propertyKey) || {
      writable: true,
      configurable: true
    };
    // 实例化修饰类
    descriptor.value = params ? new typeClass(params) : new typeClass();
    Reflect.defineProperty(
      (target && target.prototype) || target,
      propertyKey,
      descriptor
    );
  };
};

解读这段实现之前,先引出了另一个概念–反射,就是在运行时动态获取一个对象的一切信息,包括方法/属性等等,特点在于动态类型反推导。

Reflect是ES6新增的api,本身提供了不少静态方法,不过要使用还需要引入 reflect-metadata这个库,为了使编译器在设计时将元数据序列化传给修饰器。

通过反射能获得系统提供的metadataKey信息:

  • design:type修饰目标对象的类型;
  • design:paramtypes修饰目标对象方法的参数类型;
  • design:returntype修饰目标对象方法返回值的类型;

来看下案例:

import "reflect-metadata";

const validate = () => {
  return (target: any, propertyKey: string) => {
    // 修饰目标对象的类型
    let type = Reflect.getMetadata("design:type", target, propertyKey);
    // 修饰目标的参数类型
    let paramTypes = Reflect.getMetadata(
      "design:paramtypes",
      target,
      propertyKey
    );
    // 修饰目标的返回值类型
    let returnType = Reflect.getMetadata(
      "design:returntype",
      target,
      propertyKey
    );
    // 所有能通过反射获取的元数据类型key
    let allKeys = Reflect.getMetadataKeys(target, propertyKey);
    console.log("type", type);
    console.log("paramTypes", paramTypes);
    console.log("returnType", returnType);
    console.log("allKeys", allKeys);
  };
};

class Person {
  private name: string;

  @validate()
  getInfo(tags: string): string {
    return `your name is ${this.name}, tags is ${tags}`;
  }
}

控制台展示:

type function Function() { [native code] }
paramTypes [ [Function: String] ]
returnType function String() { [native code] }
allKeys [ 'design:returntype', 'design:paramtypes', 'design:type' ]

特别注意:design:returntype依赖于所修饰方法的是否显式定义类型了,如果没有定义类型,那就会默认返回 undefined

我们也可以自定义 metadataKey,即在相应的类上定义自定义的元数据。

const service = () => {
  return (target: any) => {
    // 自定义元数据,key 为 ServiceDecorator
    Reflect.defineMetadata("ServiceDecorator", "your personal value", target);
  };
};

@service()
class Person {
  private name: string;
}

// 在合适的位置获取之前定义的元数据
// your personal value
console.log(Reflect.getMetadata("ServiceDecorator", Person));

自此,有了这个知识,在看上面的 Autowired代码是不是简单的多了。

Autowired注解的本质是一个属性修饰器,主要是考虑到会有参数传入,所以就写了一个高阶函数。修饰器本身就不做介绍了,可以看下阮一峰老师的es6教程。

在方法内部,先获取了被修饰对象的类型,转换如下:

let typeClass = Reflect.getMetadata("design:type", target, propertyKey);

这个 metadataKey是系统提供的 design:type,获取被修饰对象的类型。

@Autowired()
userService: UserService;

那这个 typeClass的值就是 UserService

// 获取指定对象属性的描述对象
const descriptor = Reflect.getOwnPropertyDescriptor(target, propertyKey) || {
      writable: true,
      configurable: true
    };

这里就是获取 UserControlleruserService属性的描述对象,那这个值有什么用呢?

Reflect.getOwnPropertyDescriptor方法其实等同于 Object.getOwnPropertyDescriptor,它会返回一个object:

{
    value: "value",
    writable: true,
    enumerable: true,
    configurable: true
}

返回的四个字段中value就是这个属性的值,我们只要修改这个value字段,就可以实现注入了。

descriptor.value = params ? new typeClass(params) : new typeClass();
Reflect.defineProperty(
  (target && target.prototype) || target,
  propertyKey,
  descriptor
);

所以,最后修改了这个属性的描述对象的值,使它指向了所返回类型的实例对象,再重新定义这个属性的描述对象,这样编译后,userService这个被修饰的属性就是UserService的实例对象,能够访问到UserService内的属性方法了。

如此,就实现了 Autowired注解的功能了。

完整示例:

const Autowired = (params: any = ""): Function => {
  return (target: any, propertyKey: string) => {
    // 获取该属性的类型
    let typeClass = Reflect.getMetadata("design:type", target, propertyKey);
    const descriptor = Reflect.getOwnPropertyDescriptor(
      target,
      propertyKey
    ) || {
      writable: true,
      configurable: true
    };
    // 实例化修饰类
    descriptor.value = params ? new typeClass(params) : new typeClass();
    Reflect.defineProperty(
      (target && target.prototype) || target,
      propertyKey,
      descriptor
    );
  };
};

class UserService {
  getUserById(id: string) {
    return `user id is ${id}`;
  }
}

class Person {
  @Autowired()
  private userService: UserService;
  
  getUserInfo(id: string) {
    console.log(this.userService.getUserById(id));
  }
}

// user id is 12
console.log(new Person().getUserInfo("12"));

原文地址

【eggjs】npm start 后,中间件中的代码一直被执行。

$
0
0

1、中间件代码 sharp_rotate.js

'use strict'
module.exports = () => {
  return async function sharpRotate(ctx, next) {
    const start = Date.now()
    await next()
    console.log('rotate 时间消耗: ', Date.now() - start, 'ms')
  }
}

2、中间件配置 config.default.js

middleware: ['sharpRotate', 'errorHandler'],

3、执行 npm start本地mac OS环境正常 linux-64环境中间件代码一直被执行

image.png


【北京】美团点评-美团平台-前端开发

$
0
0

岗位职责

  1. 结合业务的特点,探索行业前沿技术方向,负责业务需求的前端方案设计、需求把控、核心功能开发;
  2. 将业务需求拆解细化并实施,保障业务快速、有序迭代;
  3. 参与产品的架构规划、性能优化、故障排查和解决等工作;

岗位要求

岗位基本要求

  1. 计算机或相关专业本科以上学历,三年以上的前端领域开发经验,能独立完成前端开发工作;
  2. 有独立的产品意识,能负责一个完整的项目技术选型推进实施
  3. 熟悉 Javascript / HTML / CSS / HTTP,了解 W3C 标准与 ES 规范,熟悉 Web 语义化和相关前端技术;
  4. 熟悉 Node.js 的开发,熟练掌握 Node 生态工具的运用;
  5. 良好的前端架构能力,熟练目前各类主流前端框架(React / VUE / Anguar 之一)并深刻理解相关实现原理;
  6. 能独立思考,分析、解决和归纳一类问题;
  7. 具有良好的工程方法和开发能力;

具备以下者优先

  1. 热爱互联网和新技术,具有极强的快速学习能力,研究过优秀开源软件的源码并有心得者优先;
  2. 开发过有影响力的开源产品;
  3. 有“代码洁癖”、有极客精神;
  4. 曾在知名互联网公司就职;

岗位亮点

  1. 配合业务快速发展需要,满足复杂多样的技术需求,跟随业务一起成长;
  2. 能和互联网一流研发团队的技术大牛一起,综合学习,共同进步。

工作地点

北京

简历投递

发送邮件:zengjun06@meituan.com

公司简介

美团的使命是“帮大家吃得更好,生活更好”。作为中国领先的生活服务电子商务平台,公司拥有美团、大众点评、美团外卖、美团打车、摩拜单车等消费者熟知的 App,服务涵盖餐饮、外卖、 打车、共享单车、酒店旅游、电影、休闲娱乐等 200 多个品类,业务覆盖全国 2800 个县区市。

2018 年 9 月 20 日,美团点评(股票代码:3690.HK)正式在港交所挂牌上市。

当前,美团战略聚焦 Food+Platform,正以“吃”为核心,建设生活服务业从需求侧到供给侧的多层次科技服务平台。与此同时,美团正着力将自己建设成为一家社会企业,希望通过和党政部门、高校及研究院所、主流媒体、公益组织、生态伙伴等的深入合作,构建智慧城市,共创美好生活。

mysql的回调函数里面的参数 err 是啥结构的?

$
0
0

conn.query(sql, parmes, function (err, result) {}

这里的err到底是啥结构的呢?按照网上的实例: console.log(’[ERROR ] - ', err.message); 显示的是:

WARN_DATA_TRUNCATED: Data truncated for column ‘age’ at row 1 应该是一个字符串吧,那么message是属性名称吗?

然后我把 err变成字符串

console.log('[INSERT err2 ] - ',JSON.stringify(err) );
显示的是:

{ “code”:“WARN_DATA_TRUNCATED”, “errno”:1265, “sqlMessage”:“Data truncated for column ‘age’ at row 1”, “sqlState”:“01000”, “index”:0, “sql”:“INSERT INTO node_user(id,name,age) VALUES(0,‘name11’,‘3w3’)”}

但是这里面怎么没有 message?上面那个 err.message 是哪来的?

然后我又直接输出

console.log(’[INSERT err ] - ',err); 这次显示的内容就多了 { Error: WARN_DATA_TRUNCATED: Data truncated for column ‘age’ at row 1 at Query.Sequence._packetToError (D:\nodejs\node_modules\mysql\lib\protocol\sequences\Sequence.js:47:14) at Query.ErrorPacket (D:\nodejs\node_modules\mysql\lib\protocol\sequences\Query.js:77:18) at Protocol._parsePacket (D:\nodejs\node_modules\mysql\lib\protocol\Protocol.js:278:23) at Parser.write (D:\nodejs\node_modules\mysql\lib\protocol\Parser.js:76:12) at Protocol.write (D:\nodejs\node_modules\mysql\lib\protocol\Protocol.js:38:16) at Socket.<anonymous> (D:\nodejs\node_modules\mysql\lib\Connection.js:91:28) at Socket.<anonymous> (D:\nodejs\node_modules\mysql\lib\Connection.js:502:10) at emitOne (events.js:115:13) at Socket.emit (events.js:210:7) at addChunk (_stream_readable.js:264:12) -------------------- at Protocol._enqueue (D:\nodejs\node_modules\mysql\lib\protocol\Protocol.js:144:48) at Connection.query (D:\nodejs\node_modules\mysql\lib\Connection.js:200:25) at Object.exports.query (D:\nodejs\test\natureFW\dbHelp.js:46:10) at Object.<anonymous> (D:\nodejs\test\NatureTest\testAdd.js:55:12) at Module._compile (module.js:624:30) at Object.Module._extensions…js (module.js:635:10) at Module.load (module.js:545:32) at tryModuleLoad (module.js:508:12) at Function.Module._load (module.js:500:3) at Function.Module.runMain (module.js:665:10) code: ‘WARN_DATA_TRUNCATED’, errno: 1265, sqlMessage: ‘Data truncated for column ‘age’ at row 1’, sqlState: ‘01000’, index: 0, sql: ‘INSERT INTO node_user(id,name,age) VALUES(0,‘name11’,‘3w3’)’ }

这回一下子多了好多。都是啥?

这大概是一个函数把,有属性和方法,JSON.stringify()好像只是把属性的部分给变成字符串了,其他的似乎没关。

Luda 一个为设计师和开发者创建的 UI 框架

$
0
0

自己写的一个前端 UI 框架。轻量级,模块化,提供多主题支持( 1.0.0 版本之后)。

内置基线网格和常用组件,基于 MutationObserver,不需要手动维护组件生命周期。

主页: https://oatw.github.io/luda

Repo: https://github.com/oatw/luda

欢迎提 issue 开 PR。

谢谢!

阿里云招前端&&Java

$
0
0

本招聘常年有效,更新时间 2019-05-06

关于我们

业务上:负责阿里云官网&营销、商业化流程构建体验及效率、横向交叉售卖能力、销售和合作伙伴 CRM 平台、天猫网厅(手机充值、流量充值、加油卡、有戏陪玩等等)、阿里通信。技术上:我们拥有开源工具 Dawn 作为项目工程化流程编排,并开源;探索 Serverless 给端开发者带来的效率提升以,通过类 GraphQL+Serverless 实现接口聚合,减少前后端沟通成本;并沉淀为能力实现独立的 NoOps 应用,实现垂直领域的业务能力建设,比如:搭建体系、流程引擎、中后台配置体系等。

我们是「阿里云事业群-业务中台-体验技术部」,主要负责阿里云售卖中台、自动化营销中台,以及云生态平台:云市场、企业服务、云栖社区、云栖大会等产品。我们对外致力于改善售卖链路优化、营销触达、生态建设、完善文档及api建设,对内focus在营销工具自动化、销售工具智能化和数据化。同时,负责业务中台全栈相关的「工程体系、开发框架、组件体系、工具及平台」的研发工作,以横向支持各产品线和项目组,为部门、为公司提效。我们是技术控,新技术先行者,大平台、多业务可以让你随意发挥,我们看重结果,也看重过程中你的探索;我们非纯技术控,一切技术创新为业务服务,业务智能化、数据化、平台化是我们对业务的追求,我们希望至少做半个pd,深入参与业务讨论。

职位描述

  • 方向一:全栈售卖中台,参与抽象售卖的核心层、场景层、开放api层的建设
  • 方向二:自动化营销中台,参与可视化配置营销体系、底层营销自动化配置体系建设
  • 方向三:生态体系,参与社区、云市场、云栖大会等建设
  • 方向四:平台架构组,参与工程化工具、框架、数据平台等建设

全栈岗位要求

  • 两年以上互联网行业前端工作经验;
  • 基础编程知识牢靠,熟悉面向对象编程、熟悉函数式编程;
  • 前端技术扎实,关注对新事物和技术,熟悉主流前端开发思想;
  • 擅长 JavaScript,熟悉 ES2015,擅长 CSS,了解相关的前端生态;
  • 擅长 React,了解 React 的核心思想,熟悉 Redux/MobX 理解它们解决的问题;
  • 了解前端模块化,能够编写出易于维护的前端代码;
  • 熟悉 Node.js,能够用 Node.js 编写工程工具或 Restful API
  • 会使用 Webpack 或 Gulp 等前端构建工具实现开发流程自动化;
  • 了解测试的重要性,熟悉测试驱动开发,熟练编写单元测试、E2E 测试;
  • 熟练使用常用的 Git 操作,熟悉基于 Git 的常见协作规范及流程;
  • 执行力强,有良好的分析、总结能力,能够有效识别痛点、并找到的解决方案;
  • 良好的团队协作精神、利用自身技术能力提升团队整体研发效率;

Java岗位要求

  • JAVA基础扎实,熟悉io、多线程、集合等基础框架,熟悉分布式、缓存、消息等机制;
  • 两年以上使用java进行开发的经验,熟练使用spring 、Mybatis等框架,熟悉Linux下的常用命令,熟悉MySQL;
  • 熟悉常用设计模式,有大型分布式、高并发、高负载、高可用性系统设计开发经验
  • 具有良好的抽象设计能力,思路清晰,善于思考,能独立分析和解决问题,责任心强,具备良好的团队合作精神和承受压力的能力;
  • 具有良好的项目规划和决策能力,善于捕捉业务需求、架构设计中存在的问题,并给出有效的解决措施和方法;
  • 具备自然语言处理、文本挖掘、数据挖掘、机器学习等算法能力优先。

加分内容

  • 参与知名开源项目,或在 GitHub 上有超过 500 star 的个人项目;

简历传送门

【实习】【滴滴出行】web前端研发实习生 部门直招

$
0
0

部门介绍

网约车策略与技术部是滴滴的核心部门,这里有牛人老板和队友、广阔的发展空间,这里将有优秀的导师指引,有快速发展的业务锻炼机会,能够接触到业界最新的技术。

我们对你的期望

  1. 本科及以上学历
  2. 2020年及之后毕业
  3. 熟悉 Javascript、CSS、HTML等
  4. 了解基本常用算法和设计模式
  5. 了解前端工程化
  6. 了解React 、redux、react-router或者vue以及相关生态
  7. 实习3个月以上

加分项

  1. 使用过webpack、git等相关工具
  2. 本科及以上学历
  3. 能快速学习,能够阅读英文文档
  4. 拥有良好的编程习惯,沟通能力佳
  5. 有node研发经历
  6. 有知名公司实习经历

你将得到

  1. 浓厚的技术氛围
  2. 晚餐补助+9点后打车免费
  3. 免费零食水果
  4. 弹性工作时间

简历投递

【邮箱地址】: liuhongboliuhongbo_i@didiglobal.com【邮件标题】:前端实习-姓名-学校-预计实习时长 hint:邮件请附上简短介绍;简历中不要提到过多和前端无关且不能体现你能力的项目,如果有项目地址,请附上

其他

提供有竞争力的实习生薪酬,能力强者可以发出新锐级别的实习生offer;有转正机会,去年实习生基本都转正了~

找到 AI - 基于机器学习的产品推荐引擎

$
0
0

Hello 大家好,

我们推出了一款基于机器学习的产品推荐引擎 - 找到AI

如果你 1 )不满足于现有的产品,需要寻找更好的可替代品; 2 )想要拓宽自己的工具箱,发现更多好产品; 3 )寻找与自己品味类似的人喜欢的产品并关注他们,欢迎使用 找到AI Ta 可以帮助你找到更多更好的互联网产品,和类似他们的产品,建议登录后查看 AI 推荐或关注其他人的推荐,AI 会基于你的行为偏好以及与你类似的人群进行智能推荐。

我们正在不断学习改进以帮助您找到下一个好产品/作品,未来我们也会逐步扩宽品类帮助你发现更多好东西,比如互联网相关书籍等。欢迎反馈意见或提交产品/作品给我们~ hi@zhaodao.ai

为什么说node具有高并发优势

$
0
0

很多人质疑node的高并发优势,并且以输出HelloWorld或输出计算结果来和传统的Java对比证明node并没有web的高并发优势,但事实真的是这样么?为什么说只输出HelloWorld性能还是比不过传统Java?异步是否还难道是不如多线程?

尤其是对于node的高并发优势,很多人却说的很模糊,所以我觉得是时候以更通俗的语言和更接近Web编程的实际场景来解释异步模型的优势。

先讲个小故事

C是建筑工,Q是搬运工,Y是包工头。

故事一:第一天C建墙建了一天发现没砖了,C告诉包工头Y没砖了,于是Y通知Q去搬点砖来,结果Q搬砖搬了一天,C就休息了一天。后来C建了一天屋顶又发现没瓦了,C告诉包工头Y没瓦了,于是Y通知Q再去搬点瓦来,结果Q搬瓦搬了一天,C就又休息了一天。后来C建了一天窗户又发现没玻璃了,C告诉包工头Y没玻璃了,于是Y通知Q再去搬点玻璃来,结果Q搬玻璃搬了一天,C就又休息了一天。后来C建了一天电路又发现没电线了,C告诉包工头Y没电线了,于是Y通知Q再去搬点电线来,结果Q搬电线搬了一天,C就又休息了一天。以此类推,最终导致工期没有按时完成,Y被处分了。

故事二:吸取了故事一的教训,Y扩充了三倍团队人数。C1,C2,C3一起来建房子。结果C1,C2,C3都没有砖了,C1,C2,C3告诉Y,Y于是叫Q1,Q2,Q3去搬砖。同样Q1,Q2,Q3搬砖搬了一天,C1,C2,C3就休息了一天,和上面差不多都出现了搬瓦搬玻璃电线等等事件,但由于人多,建的速度快,还好没延期,但多招了很多人,Y亏本破产了。

故事三:吸取了故事二的教训,Y决定弄个排期表还是不能让C闲着,当C建了一天墙发现没砖了后,Y让Q把砖搬回来的同时也让C先建设一天屋顶。正好C发现没瓦后,正好S的砖也搬回来了,C又可以去建墙,同时S又可以去拉瓦。当瓦拉回来后,C又可以建屋顶了。以此类推,最终工期按时完成,同时Y也赚到盆满钵满。

故事一就是传统的单线程阻塞模式,故事二就是多线程的阻塞模式,故事三就是非阻塞的异步模式。而C就是CPU,C休息就是CPU空转。Q就是查询,Q搬东西就是查询需要等待的时间。C1,C2,C3的工资就是开线程的成本。Y就是你,你就是包工头。所以非阻塞的异步模式,主要解决了两个问题:

  • 解决了CPU空转大量浪费问题
  • 节约了开线程和线程切换上下文的成本问题

再谈什么情况能超越传统Java

根据上面的情况,无论是只输出HelloWorld也好,进行少量计算也好,这都是无需等待的操作,相当于上面那个故事里面的砖从来没有缺过的情况,但是一旦涉及到需要阻塞的等待,那么node的异步模式将起了极大的作用,而Web编程这种需要阻塞的等待又是极多的,比如说查询。

我将用一段Java和node的等待操作进行压测来证明我的所说的情况。

java代码:

package test;

import javax.servlet.http.HttpServlet;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import java.io.*;

@WebServlet("/")
public class TestServlet extends HttpServlet {

	public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
		// 暂停三秒
		int sleepTime = 3000;
		try {
			Thread.sleep(sleepTime);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		PrintWriter out = response.getWriter();
    // 读取文件并显示,unuseData.txt是一个40M的文件
		File f = new File("/xxx/unuseData.txt");
        FileInputStream fip = new FileInputStream(f);
        InputStreamReader reader = new InputStreamReader(fip, "UTF-8");
        StringBuffer sb = new StringBuffer();
        while (reader.ready()) {
            sb.append((char) reader.read());
        }
        reader.close();
        fip.close();
		out.println("Java Stop The World " + sleepTime/1000 + "s"+",unuseData:"+ sb.toString());
	}

}

node代码:

const http = require("http");
const fs = require("fs");
const port = 4000;
function nodeSleep(time) {
    return new Promise((resolve,reject)=>{
        setTimeout(() => {
            resolve(true)
        }, time);
    });
}
function getUnseData() {
    return new Promise((resolve,reject)=>{
        // unuseData.txt是一个40M的文件
        fs.readFile('/xxx/unuseData.txt', (err, data) => {
            if (err) reject(err);
            resolve(data)
        });
    });
}
http.createServer( async function (request, response) {
    let sleepTime = 3000;
    // 暂停三秒
    await nodeSleep(sleepTime);
    // 读取文件并显示
    let unuseData = await getUnseData();
    response.end(`Node Stop The World ${sleepTime}s,unseDate:${unuseData}`);  
}).listen(port);
console.log(`listen http://localhost:${port}/`)

压测结果:

# Java
ab -n 50 -c 5 http://localhost:8080/test/
Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.1      0       1
Processing:  4181 5645 883.3   5579    7495
Waiting:     4075 5443 838.2   5394    7215
Total:       4181 5645 883.3   5579    7496

# Node
ab -n 50 -c 5 http://localhost:4000/
Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.3      0       2
Processing:  3210 3487 232.7   3487    3908
Waiting:     3182 3349 167.8   3328    3835
Total:       3210 3487 232.7   3488    3908

注意:并发为5,总请求数为50是因为我电脑是公司的低配mini扛不住,机器好的可以适当调高

可以看到

Java最快在5秒左右,最慢在7秒左右。

Node最快在3秒左右,最慢也在3秒左右。

传统的Java写法居然比Node慢了2到4秒!

为什么呢?

先解释一下代码,这两段代码都是先sleep一段时间,再读取文件展示给页面上。但Node在等待的时候让另一个已经等待完成的请求来读文件了,传统的Java却只能将等待彻底完成,才开始读文件,并且由于服务tomcat的worker恒定,worker池用完后,则需要等待worker释放,导致后一个worker的时间极大延长,而Node的队列却足够长到可以应付。

所以为什么只是少量计算或直接输出HelloWorld,压测时性能还不如Java是因为这个时候CPU直接打满,这会导致node直接就阻塞了,无法发挥其优势,而这时Java的多worker反而使得CPU打满充分利用CPU来计算,所以速度反而快了。

但是Web编程的大部分情况都不是简单的少量计算或直接输出HelloWorld,而是往往有更多的查询或文件读写操作和更复杂的情况,所以导致Node在通用Web开发中具有更大高并发优势!


哪位大神实践过在阿里云函数计算中webpack打包发布

$
0
0

阿里云函数计算,是个诱人的服务,我们在试水。

但是现在遇到webpack打包后,本地调试云函数时,找不到handler入口函数的问题

有成功实践webpack打包后发布到云函数计算的吗?

有没有朋友接私活,报酬 5万-10万

$
0
0

image.png

每天更新外包资源,尽在微信小程序:小猿众包 。扫一扫

image.png

可以加官方微信群: image.png

计算机语言的性能指标都是啥意思?

前端如何做excel表格的导出

Nodejs对于大文件分片的思考

$
0
0

nodejs中对于大文件一般是用stream来操作的,但是对于更大的文件,处理还是很耗时间。所以我就想能不能用子进程结合fs.createReadStrem的方式,使用其中的start,end来进行文件分片,再交由子进程读取后使用process.send发给主进程。但是自己写的代码发现往往比单进程还要耗时,请问我这样的思考方向有问题吗?另外,现在我学nodejs纯粹是想到哪写到哪,请问有没有什么好的nodejs书籍或者在线学习的地方推荐?劳烦各位解疑了,谢谢。

Viewing all 14821 articles
Browse latest View live