Jude

Jude 查看完整档案

广州编辑  |  填写毕业院校  |  填写所在公司/组织 myfjdthink.com 编辑
编辑

myfjdthink.com

个人动态

Jude 赞了文章 · 2020-04-03

Mac 解决 gyp: No Xcode or CLT version detected! 报错

我的macOS版本是macOS Catalina 10.15.2

在执行npm install下载项目的依赖包的时候出现的gyp报错,报错内容如下:
No receipt for 'com.apple.pkg.CLTools_Executables' found at '/'.

No receipt for 'com.apple.pkg.DeveloperToolsCLILeo' found at '/'.

No receipt for 'com.apple.pkg.DeveloperToolsCLI' found at '/'.

gyp: No Xcode or CLT version detected!
gyp ERR! configure error
gyp ERR! stack Error: `gyp` failed with exit code: 1

后面还有一长串,就不全粘在这里了,主要的就是xcode出现错误,本人也是个小白,在网上搜了很久,大家给的解决方案大部分都是执行指令:

xcode-select --install

还有说要将npm和node的版本升级到最高的,我试过了,都没有解决我的问题。
最后是在没有办法了,我寻思不是Xcode出现问题了吗,我就在App Store里面把那个软件开发工具给下载下来了,我下的是最新版本Xcode 11.3,然后启动一下Xcode,把那个服务条例的同意点了,然后在执行npm install下载项目依赖包,就好使了。。。
我也不晓得具体是咋回事,我猜是因为macOS最近的更新更改了系统的底层文件,操作原先的文件即使提示已经安装,但是由于系统更改了底层文件,也无法解决报错。

注意:

  • 我在安装完Xcode的时候,点击同意条款后,出现cpu飙到95%以上,而且vscode卡死的情况,我是把电脑关机了,然后再启动电脑解决的问题,这个问题大家注意一下
  • 如果本机已经有Xcode软件开发工具的,看一下自己的Xcode是不是最新的,听说这玩意不会自动更新或者不报更新,更新完毕后一定要记得去打开Xcode点击一下同意条款
查看原文

赞 22 收藏 5 评论 10

Jude 发布了文章 · 2019-12-25

使用注解简化 Mongoose 事务的使用

mongoose 提供的事务

MongoDB 4.0 开始提供了事务支持,mongoose 也提供了相应的实现,不过目前的写法还是比较繁琐。
我们看一下 mongoose 给出的 demo

const Customer = db.model('Customer', new Schema({ name: String }));

let session = null;
return Customer.createCollection().
  then(() => db.startSession()).
  then(_session => {
    session = _session;
    // Start a transaction
    session.startTransaction();
    // This `create()` is part of the transaction because of the `session`
    // option.
    return Customer.create([{ name: 'Test' }], { session: session });
  }).
  // Transactions execute in isolation, so unless you pass a `session`
  // to `findOne()` you won't see the document until the transaction
  // is committed.
  then(() => Customer.findOne({ name: 'Test' })).
  then(doc => assert.ok(!doc)).
  // This `findOne()` will return the doc, because passing the `session`
  // means this `findOne()` will run as part of the transaction.
  then(() => Customer.findOne({ name: 'Test' }).session(session)).
  then(doc => assert.ok(doc)).
  // Once the transaction is committed, the write operation becomes
  // visible outside of the transaction.
  then(() => session.commitTransaction()).
  then(() => Customer.findOne({ name: 'Test' })).
  then(doc => assert.ok(doc));

这个 demo 暴露了两个问题:

  1. 需要为每一个事务里做提交和回滚的处理
  2. 事务是用 session 来区分的,你需要一直传递 session

使用注解

所以 akajs 提供了一个事务的注解来简化这个处理流程。

import * as mongoose from 'mongoose'
import {Schema} from 'mongoose'
import * as assert from 'assert'
import {Transactional, getSession} from './decorators/Transactional'

mongoose.connect('mongodb://localhost:27017,localhost:27018,localhost:27019/test?replicaSet=rs', {useNewUrlParser: true})
mongoose.set('debug', true)
let db = mongoose.connection
const Customer = db.model('Customer', new Schema({name: String}))

class ClassA {
  @Transactional()
  async main (key) {
    await new Customer({name: 'ClassA'}).save({session: getSession()})
    const doc1 = await Customer.findOne({name: 'ClassA'})
    assert.ok(!doc1)
    await new ClassB().step2()
    return key
  }
}

class ClassB {
  async step2 () {
    const doc2 = await Customer.findOne({name: 'ClassA'}).session(getSession())
    assert.ok(doc2)
    await Customer.remove({}).session(getSession())
  }
}

new ClassA().main('aaa').then((res) => {
  console.log('res', res)
  mongoose.disconnect(console.log)
}).catch(console.error)

解析:

  • @Transactional() 注解会自动提交或回滚事务(发生异常时)。具体实现见Transactional.ts ,核心实现部分,使用 try catch 捕获异常,实现自动回滚。
try {
  const value = await originalMethod.apply(this, [...args])
  // Since the mutations ran without an error, commit the transaction.
  await session.commitTransaction()
  // Return any value returned by `mutations` to make this function as transparent as possible.
  return value
} catch (error) {
  // Abort the transaction as an error has occurred in the mutations above.
  await session.abortTransaction()
  // Rethrow the error to be caught by the caller.
  throw error
} finally {
  // End the previous session.
  session.endSession()
}
  • 为了避免嵌套调用时,你需要一直传递 session 的尴尬~,akajs 提供全局的 getSession() 方法,其实现原理是依赖 Async Hooks ,是 Node 的实验性特性,

你对此介意的话,请不要在生产环境使用。

注意 mongodb 的事务必须在复制集上使用,在开发环境启动 mongodb 复制集,推荐使用 run-rs

更进一步

当然,在每一个需要 Session 的地方调用 getSession() 方法还是稍显累赘,我们可以通过 wrap mongoose 的各个方法,来实现自动注入 session。

例如把 mongoose 的 findOne 方法替换为

let originFindOne = mongoose.findOne
mongoose.findOne = () => {
originFindOne().session(getSession())
}

但是工作量有些多,暂时没时间做。

查看原文

赞 1 收藏 0 评论 0

Jude 发布了文章 · 2019-12-17

Node+MongoDB+TypeScript 开发后端服务的一些实践

最近把这些年使用 Node 做后端服务的一些实践总结了一下,做成一个脚手架实例项目,名为 akajs

akajs 实际上是一些后端实践的集合,最初的想法是对公司的实际开发业务常用流程进行封装,减少重复开发。

现在开源出来,目的也不是为了提供一个 web 框架,只是想展示一下,在 Web 后端开发领域,我们是如何做的。

akajs 包括以下内容:

  • 模块化组织方式、系统较为复杂的时候需要
  • 注解式路由,类似 nest 或 Spring
  • ICO 依赖注入
  • 参数和返回值处理和错误处理
  • Mongoose 搭配 typescript + ioc
  • 注解式 Mongoose 事务
  • CRUD 一键生成
  • 日志和健康检查
  • 常用函数工具,如日期、数字等
  • 集成测试方案

详细内容请查看文档

查看原文

赞 3 收藏 3 评论 0

Jude 发布了文章 · 2016-12-02

用 js 写个自动寻路的贪吃蛇

前言

偶尔看到两年前写的贪吃蛇,当时没把自动寻路的算法写好,蛇容易挂,周末找了个时间把当年的坑填上,写了个不会挂的贪吃蛇。

两年前的版本_点击查看

这次更新的版本_点击查看

代码比较简单,使用 canvas 完成游戏的画图,抛开 A* 算法的实现,整个 html 代码在 300 行以内~
源码 :
https://github.com/myfjdthink...

原理说明

不死的方法

首先要找出一个模式可以保持蛇不挂,这个模式就是
“跟着尾巴跑”

如果蛇头和蛇尾是可以连通的,那么就不会挂。
所以只要保证任意时刻蛇头和蛇尾能连通即可。
寻路的伪代码如下:

if(head to  flood){ // 蛇头能连通食物
    模拟蛇吃到食物后的状态
    if(newHead to tail){   // 吃到食物后还能连接尾巴 安全
        eat flood
    }  else {
        // 吃到食物后无法连接尾巴 放弃
        flow tail
    }
} else {
    flow tail   // 跟着尾巴跑
}

在吃食物之前,需要模拟吃到食物后蛇的状态,判断此时蛇是否还能连接尾巴,由此决定是否吃掉食物。

如何找到最短路径

使用 A* 算法可以快速找到俩点之间的最短路径,网上找了个实现,就直接扒下来使用啦。
http://devpro.it/examples/ast...

TODO

目前只是实现了不死,在某些条件下,程序还是会陷入一个循环,这个有空在改进吧,欢迎提 PR。

查看原文

赞 2 收藏 3 评论 1

Jude 回答了问题 · 2016-12-01

解决nodejs 获取两个异步查询的结果

先去了解下 async 这个异步流程控制的库

针对你这个 case 够了

async.parallel([
    $search1,
    $search2
], function(err, results) {
    // optional callback
});

要深入了解 node 的异步控制的话,还是去系统学一下 node 异步同步的知识吧
异步操作和Async函数

关注 6 回答 5

Jude 关注了问题 · 2016-11-30

mongodb怎么对分组,不要统计

mongo.getCollection('t_app').aggregate([
        {
            $group: {
                _id: {
                    FuncName: "$FuncName",
                    Platform: "$Platform",
                    UseDateTime:{  $dateToString: { format: "%Y-%m-%d", date: "$UseDateTime" }}
                }
            }
        }
    ]

上面只是一个构想。。。,我想根据这些key的字段要求,进行分组,,不需要统计,完整的应该怎么写?

关注 2 回答 1

Jude 回答了问题 · 2016-11-30

mongodb怎么对分组,不要统计

$push

把结果 push 到数组里就行了。

mongo.getCollection('t_app').aggregate([
        {
            $group: {
                _id: {
                    FuncName: "$FuncName",
                    Platform: "$Platform",
                    UseDateTime:{  $dateToString: { format: "%Y-%m-%d", date: "$UseDateTime" }}
                },
                result : {$push : "$Platform"}
            }
        }
    ]

关注 2 回答 1

Jude 发布了文章 · 2016-11-30

JS 里怎么给数组填充默认值

今天看到一段代码:

Array.apply(null, Array(30)).map(() => 4)

这代码的写法无法让人一下理解它的意图。
Google 之后知道它的作用是构造一个长度为 30 的数组,默认值是 4。

解析

但是为什么要写得这么别扭呢?我们来分解下它每一步在做什么:

Array.apply(null, Array(30)) 

这一段代码生成一个长度为30的数组,里面的值都是 undefined
之后的 .map(() => 4) :负责填充默认值

但是为什么构造一个空值数组需要这么麻烦呢?还要用上 apply 方法,尝试用 Array(30).map(() => 4) 来生成数组的话,你会得到这样的一个结果,根本就没有值。

[ , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ]

查看文档 可以看到 Array 的构造函数语法,可以得知 Array 支持两种构造方式。使用参数形式给定 N 个数组元素,或者给定一个数组长度。
不过比较重要的一点文档里没提到,使用 new Array(arrayLength) 方式构造的数组是一个稀疏数组,里面是没有任何值的,只有长度。所以这个方式构造出来的数组是无法遍历的,也就无法用 map 遍历填充值了。

知道了上述的原因,我们就能理解:

Array.apply(null, Array(30))
其实等于
Array.apply(null, [, , , , , , , , , , , , , , , , , , , , , , , , , , , , ,]))

然后我们要继续了解 apply 方法,在这里可以看 apply 的作用 文档解释, 这里不作介绍。apply 方法会把生成的稀疏数组展开并当做参数再次传给 Array 的构造函数,就是这样子:

Array(null,null,null......))

这样最终就会得到一个数组,这样就不是稀疏数组了,里面是有值的,虽然是 undefined。

[ undefined, undefined, undefined ......]

结语

总结下,其实就是 js 的 Array 的默认构造函数生成的是稀疏数组,是无法用 map 遍历填充的。所以才写得这么绕。

不过,说了这么多,要实现原本的需求,其实有更简单的方法啦:

Array(30).fill(4)

fill 方法的说明

查看原文

赞 14 收藏 13 评论 4

Jude 关注了问题 · 2016-11-30

解决使用web api做接口 跨域请求的时候 会405 直接访问这个接口没问题 怎么破

如题 vue 项目 前后端分离 使用 web API 做服务器接口 ajax 跨域请求的时候会 405 直接访问这个接口没问题 应该怎么破 求帮助 错误如下图
clipboard.png

关注 5 回答 4

Jude 回答了问题 · 2016-11-30

解决使用web api做接口 跨域请求的时候 会405 直接访问这个接口没问题 怎么破

看这篇文章 http://www.cnblogs.com/virtua...
里面有说到

Preflighted Requests是CORS中一种透明服务器验证机制。预检请求首先需要向另外一个域名的资源发送一个 HTTP OPTIONS 请求头,其目的就是为了判断实际发送的请求是否是安全的。

在跨域请求发起之前,浏览器会发出一个预检请求,这个请求的 http method 是 OPTIONS,但是你的服务器不支持这个方法,返回了405错误。
你需要修改服务器接口,让它接受跨域请求。

关注 5 回答 4

认证与成就

  • 获得 34 次点赞
  • 获得 1 枚徽章 获得 0 枚金徽章, 获得 0 枚银徽章, 获得 1 枚铜徽章

擅长技能
编辑

(゚∀゚ )
暂时没有

开源项目 & 著作
编辑

(゚∀゚ )
暂时没有

注册于 2014-10-24
个人主页被 325 人浏览