OYRC

Que sera, sera

一些题目

- OY欧阳 JavaScript文章笔记

          

// 浏览器事件循环
async function a1() {
  console.log('a1 start') // 2
  await a2()
  console.log('a1 end') // 微任务 稍等2 7
}
async function a2() {
  console.log('a2') // 3
}
console.log('script start') // 1
setTimeout(() => {
  console.log('setTimeout') // 宏任务 等会儿 微任务也搞完了 10
}, 0)
Promise.resolve().then(() => {
  console.log('promise1') // 微任务 稍等1 栈里的搞完了开始执行微任务了 6
})
a1()
let promise2 = new Promise((resolve) => {
  resolve('promise2.then') // xx任务 反正等一下 它这是返回给then的结果所以
  console.log('promise2') // 4
})
promise2.then((res) => { // .then都是微任务 稍等
  console.log(res) // 微任务,这个res是上面resolve('promise2.then') 给过来的 8
  Promise.resolve().then(() => {
    console.log('promise3') // 微任务呀 9
  })
})
console.log('script end') // 5

// safari 的微任务推出好像顺序有点不同,

// script start
// a1 start
// a2
// promise2
// script end
// promise1
// a1 end
// promise2.then
// promise3
// setTimeout



// node 的事件循环
/**
 * nodejs的事件循环简化为三个部分,这三个部分必须按顺序执行
 * timer:setTimeout,setInterval放在这里执行
 * 
 * poll:在这里等待时间的流逝,这个阶段的时长最长,所以大部分概率是从这个点开始执行
 * 
 * check:setImmediate放在这里执行
 * 
 */








// 实现bind  简单版 不支持new
function bind1(asThis, ...args) {
  const fn = this
  return function (...args2) {
    return fn.call(asThis, ...args, ...args2)
  }
}
// 实现bind 正经版本  不支持new
var slice = Array.prototype.slice
function bind2(asThis) {
  var fn = this
  var args = slice.call(arguments, 1)
  if (typeof fn !== 'function') {
    throw new Error('bind 必须调用在函数身上')
  }
  function resultFn() {
    var args2 = slice.call(arguments, 0)
    return fn.apply(
      resultFn.prototype.isPrototypeOf(this) ? this :
        asThis, args.concat(args2))
  }
  resultFn.prototype = fn.prototype
  return resultFn
}

// 实现bind es6完整版本  支持new
function bind3(asThis, ...args) {
  const fn = this
  function resultFn(...args2) {
    return fn.call(
      this instanceof resultFn ?
        this : asThis,
      ...args, ...args2)
  }
  resultFn.prototype = fn.prototype
  return resultFn
}



//  实现一个new操作
function _new(func) {
  var res = {};
  if (func.prototype !== null) {
    res.__proto__ = func.prototype;
  }
  var ret = func.apply(res, Array.prototype.slice.call(arguments, 1));
  if ((typeof ret === "object" || typeof ret === "function") && ret !== null) {
    return ret;
  }
  return res;
}





// 二分查找
// 二分查找是需要一个有序序列,所以这里默认传递进来的是有序数组
const search = (arr, tag) => {
  let low = 0
  let high = arr.length - 1
  let mid
  while (low <= high) {
    mid = parseInt((low + high) / 2)
    if (tag === arr[mid]) {
      return mid
    } else if (tag < arr[mid]) {
      high = mid - 1
    } else if (tag > arr[mid]) {
      low = mid + 1
    } else {
      return -1
    }
  }
  return mid
}


// js 深拷贝
class DeepClone {
  constructor() {
    this.cache = []
  }
  clone(source) {
    if (source instanceof Object) {
      let cacheDist = this.findCache(source)
      if (cacheDist) {
        return cacheDist
      } else {
        let dist
        if (source instanceof Array) {
          dist = new Array()
        }
        else if (source instanceof Function) {
          dist = function () {
            return source.apply(this, arguments)
          }
          //  dist = source.bind(this, ...arguments)
        }
        else if (source instanceof RegExp) {
          dist = new RegExp(source.source, source.flags)
        }
        else if (source instanceof Date) {
          dist = new Date(source)
        }
        else {
          dist = new Object()
        }
        this.cache.push([source, dist])
        for (const key in source) {
          // for in 默认会遍历原型上的属性,所以需要加上
          if (source.hasOwnProperty(key)) {
            dist[key] = this.clone(source[key])
          }
        }
        return dist
      }
    }
    return source
  }
  findCache(source) {
    for (let i = 0; i < this.cache.length; i++) {
      if (this.cache[i][0] === source) {
        return this.cache[i][1]
      }
    }
    return undefined
  }
}

// 去除前后空格
str.replace(/(^\s)|(\s$)/g, '')


// 二叉树
let tree = {
  rt: 1,
  l: {
    rt: 2,
    l: {
      rt: 4,
      l: {
        rt: 7,
      },
      r: {
        rt: 8
      }
    },
    r: {
      rt: 5,
      r: {
        rt: 9,
        l: {
          rt: 12,
        }
      }
    }
  },
  r: {
    rt: 3,
    r: {
      rt: 6,
      l: {
        rt: 10
      },
      r: {
        rt: 11
      }
    }
  }
}
const treeOderF = (tree = {}) => {
  if (tree.rt) {
    console.log(tree.rt)
    treeOderF(tree.l)
    treeOderF(tree.r)
  }
}

const treeOderM = (tree = {}) => {
  if (tree.rt) {
    treeOderM(tree.l)
    console.log(tree.rt)
    treeOderM(tree.r)
  }
}

const treeOderB = (tree = {}) => {
  if (tree.rt) {
    treeOderM(tree.l)
    treeOderM(tree.r)
    console.log(tree.rt)
  }
}



// 事件循环
/**
 * 宏任务 ----- macrotasks -----  一会儿
 * setTimeout
 * I/O
 * UI渲染
 * 
 * 微任务 ----- microtasks ----- 马上
 * promise
 */

async function async1() {
  console.log('async1 start');// 2
  await async2();
  console.log('async1 end'); // 微任务 稍等1 6
}
async function async2() {
  console.log('async2');// 3
}
console.log('script start'); // 1
setTimeout(function () {
  console.log('setTimeout'); // 宏任务 等会儿 8
}, 0)
async1();
new Promise(function (resolve) {
  console.log('promise1');// 4 这个是立即执行的
  resolve();
}).then(function () {
  console.log('promise2'); // 微任务 稍等2 7
});
console.log('script end'); // 5 可以开始刚刚没做的了

// script start 
// async1 start 
// async2
// promise1
// script end
// async1 end // 在safari 中,这两个顺序换了过来
// promise2   // 在safari 中,这两个顺序换了过来
// setTimeout




// 带缓存的斐波那契函数
// ---------1-------------
f = (n) =>
  n === 0 ? 0
    : n === 1 ? 1
      : f(n - 1) + f(n - 2)

// 尾递归优化 斐波那契
f = (n) => f_inner(2, n, 1, 0)
f_inner = (start, end, prev1, prev2) =>
  start === end ? prev1 + prev2
    : f_inner(start + 1, end, prev1 + prev2, prev1)

// 有一个字符串str,完全由(){}[]这些字符组成,返回是否是正确匹配的括号
const isM = (str = '') => {
  let strA = [...str]
  let h = []
  let l
  strA.forEach(e => {
    l = h[h.length - 1]
    switch (e) {
      case '(':
        h.push(e)
        break;
      case ')':
        if (l === '(') {
          h.pop()
        }
        break;
      case '[':
        h.push(e)
        break;
      case ']':
        if (l === '[') {
          h.pop()
        }
        break;
      case '{':
        h.push(e)
        break;
      case '}':
        if (l === '{') {
          h.pop()
        }
        break;
    }
  })
  if (h.length) {
    return false
  } else {
    return true
  }
}






          
SHOW

记一次网站提速

- OY欧阳 https文章网站优化

这两天再给我自己的网站提速,像我这个破网站,随便优化优化,收益高得不得了。

之前有说过我的服务器是学生价买的最低配的服务器,当前使用带宽: 1Mbps,这玩意随便几张图就急得不行。

欢迎页面是仿的凤凰网招聘页,第一次看被惊艳到了,一番摸索,发现css关键属性是mask,然后就…然后就做出来了。但是用到了很多图,有些图达到了500k以上,这些图呢颜色又很丰富,去压缩,也压缩不了多少。

压缩不动啊

所以我网站在任何人电脑上第一次打开都得卡个十来秒来下图,辛辛苦苦做的动画啥都看不到,这可不行。

第一步:上传cdn

因为这些图片都是一些静态文件,是可以丢到cdn而不走自身服务器的,所以第一步就是在阿里云开了个oss,把这些图片丢上去。过程很简单,找个最便宜的资源包,买它!再弄个Bucket,新建个目录,上传图片。完事。这样一操作,图片加载速度一下就快了很多。

第二步:使用Webp

但是图片依旧是4、500k的大小,太大了,是不是有别的更小的图片类型呢?

哈!Webp!

使用Webp类型切压缩的效果

厉害了,同样的图,342k的图压缩到了57k,就这么定了!

第二部就是将全部静态图片都换成webp然后压缩一番再传到cdn上,这样一来,我这个动画效果就能完美展示,再也不会出现少图的情况了!

但是!Webp并不是所有浏览器都支持,特别是Safari,从头到位没一点绿,这就很难受,Safari上就是完全看不到这个动画了!

…这个…目前还没想到怎么解决,可能…全部换回png或者jpg吧…

先不纠结这个了,还是看看网站哪里还能再加加速。

第三部:使用GZIP

GZIP!又是压缩!要加快就是要将同样的内容用更少的数据传给客户端。

加这个也很容易,在nginx的总配置的http里添加

gzip on;
gzip_min_length 1k;
gzip_buffers 4 16k;
gzip_comp_level 2;
gzip_static on;
gzip_types text/plain application/javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png;
gzip_vary on;
gzip_disable "MSIE [1-6]\.";
# 每个属性都有对应的效果,可以去看看对应的文档。

配置好后重新启动一下nginx就好了。在看网站的对资源的请求,可以看到有Content-Encoding: gzip这么一条属性,这就说明GZIP配置成功了。

到目前位置,我的网站也就做了这三部来提高页面加载速度,不多,也不麻烦,但是效果很好(因为底子太差),其实很多正经项目都会有第一步和第三部的操作,可以说是基本操作,我在这只是作为一个初学者来学习这些东西。

其实之后还可以有第四步。

第四步:使用http 2.0

目前我所见的网站大多都还是使用的http 1.1,其实http 2.0老早就出了,http 2.0相比http 1.1/1.0优化了好多好多,简单点说就是:多路复用,二进制分帧,首部压缩,服务端推送,更多可以参考这个

以我目前的水平来看http 2.0能给我带来啥好的,我就是觉得多路复用挺好的。之前的http 1.1/1.0协议中,浏览器客户端在同一时间,针对同一域名下的请求有一定数量限制。超过限制数目的请求会被阻塞。

对我的个人网站来说,欢迎页面有很多图片,但是图片不能同时请求,只能几个几个的分批请求,但是如果使用了http 2.0则没有这个限制。

1.1和2.0加载对比

看着就很舒服是不是。

但是http 2.0需要https,这个其实也很简单,关键词:certbot,按着步骤来1、2、3分分钟就好了。

以上就是我已经或者将要对网站加载速度做的优化操作,很简单,有的也很基础,但是对那种完全没做过优化的网站来说,这些操作带来的收益是非常非常高的,一定得做。

前端菜狗,还在秃头学习,有啥不对的,敬请拍砖!

谢谢阅读~

SHOW

最近再看Vue技术内幕,就把Vue项目fork了一份,然后边看文章边在代码里加上注释。看了几节内容,做了一些笔记,准备提交一次,然后就直接:


          
git add .
git commit -m '添加代码注释'

……

          

然后就弹出这么个内容:


          
   ERROR  invalid commit message format.

  Proper commit message format is required for automated changelog generation. Examples:

    feat(compiler): add 'comments' option
    fix(v-model): handle events on blur (close #28)

  See .github/COMMIT_CONVENTION.md for more details.
  You can also use npm run commit to interactively generate a commit message.


commit-msg hook failed (add --no-verify to bypass)


          

怎么提交还会报错?这看上去不像冲突啥的啊。npm run commit 又是啥? 键入npm run commit


          
cz-cli@2.10.1, cz-conventional-changelog@2.1.0


Line 1 will be cropped at 100 characters. All other lines will be wrapped after 100 characters.

? Select the type of change that you're committing: (Use arrow keys)
❯ feat:     A new feature 
  fix:      A bug fix 
  docs:     Documentation only changes 
  style:    Changes that do not affect the meaning of the code (white-space, format
ting, missing semi-colons, etc) 
  refactor: A code change that neither fixes a bug nor adds a feature 
  perf:     A code change that improves performance 
  test:     Adding missing tests or correcting existing tests 
(Move up and down to reveal more choices)


          

选择这次提交的类型?类型有很多种,除了这些还可以用方向键查看更多的:


          
  build:    Changes that affect the build system or external dependencies (example scopes: gulp, broccoli, npm) 
  ci:       Changes to our CI configuration files and scripts (example scopes: Travis, Circle, BrowserStack, SauceLabs) 
  chore:    Other changes that don't modify src or test files 
  revert:   Reverts a previous commit 


          

选择对应的类型可以清楚明了的说明本次提交的目的。 接下来还会问一些问题:


          
? What is the scope of this change (e.g. component or file name)? (press enter to s
kip)
 
? Write a short, imperative tense description of the change:
 添加笔记以及注释
? Provide a longer description of the change: (press enter to skip)
 
? Are there any breaking changes? No
? Does this change affect any open issues? No

          

按着这个一步一步来,一个规范的的commit就出来了。 嗨呀,真的好啊,还能强制性的规范commit,所有项目上都弄这么个东西,这么一来所有项目的commit都会变得清晰明了。 这个命令到底执行了啥呢?跑去package.json文件中去看,有这么一句"commit": "git-cz"git-cz又是啥呢?接着又去google。 google git-cz 第一条点进去,是一个插件,叫commitizen。 切到自己的项目,npm安装,package.jsonscripts添加指令,再在package.jsonconfig里添加:


          
  "config": {
    "commitizen": {
      "path": "./node_modules/cz-conventional-changelog"
    }
  }

          

然后随便改点东西,先用


git add .
git commit -m 'x'

测试下。哈?怎么直接提交了?怎么没报错?这东西没用?npm run commit,这玩意儿有用呀,为啥直接提交不规范commit还能成功? 再看看vue的package.json怎么写的。


          
  "gitHooks": {
    "pre-commit": "lint-staged",
    "commit-msg": "node scripts/verify-commit-msg.js"
  },
  "lint-staged": {
    "*.js": [
      "eslint --fix",
      "git add"
    ]
  },


          

gitHooks:顾名思义,git相关的钩子,可以在git的各个时间做不同的处理。实际上想这么用得装个尤大写的yorkie,实际上就是改了一丢丢的husky

  • commit之前,执行lint-staged
  • 对commit的说明进行判定是否是符合规范的commit

lint-staged :对代码进行静态分析,试图找出潜在的问题。使用 lint-staged只会对每次提交文件进行检查。

  • 对所有提交的js文件进行eslint修复,修复后重新添加该文件到暂存区

加上这两句之后,直接提交不规范的commit就会报错啦,而且还会对提交的js文件进行eslint验证,以及尝试修复eslint。

SHOW

记一次视频流播放

- OY欧阳 学习文章视频

最近公司要做一个卖视频的产品,既然是卖视频,那视频当然得加个密,不让别人随便下载咯。而且是课程类的视频,一个视频长度都在一个小时左右,那就也得考虑流量问题。 如果是使用普通的mp4视频格式,既容易被下走,又非常浪费流量,如果用户看了前百分之十的视频内容就不想看或者想下次再看,但是以2018年的网速,说不定就已经把所有视频全都下好了,既浪费了用户的流量,也浪费了公司的流量,钱从两边都哗哗的流到了电信公司的手里。 所以需要选择一个视频看了多少,那就加载多少并且再多加载一丢丢的播放方法或者播放格式,经过公司大佬们的商量,选择了使用七牛的音视频切片。将一整个音频、视频流切割成可由HTTP下载的一个个小音视频流,并生成一个M3U8播放列表,客户端根据M3U8播放列表依次加载播放视频——即HTTP Live Streaming(HLS)播放。

常见的两种普通m3u8文件格式:

第一种:


          #EXTM3U
#EXT-X-VERSION:3
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-ALLOW-CACHE:YES
#EXT-X-TARGETDURATION:24
#EXTINF:23.200000,
/7aq_l2qC3ULNDfVn0EVIGDP_SkQ=/lkUGxqs1gCaHdB3PBj_mbywxZpLS/000000.ts
#EXTINF:11.300000,
/7aq_l2qC3ULNDfVn0EVIGDP_SkQ=/lkUGxqs1gCaHdB3PBj_mbywxZpLS/000001.ts
#EXT-X-ENDLIST

          

这种m3u8文件只是做了视频切片,可以达到节流需求,任何人拿到就可播(当然你得有个能播m3u8的播放器)。

第二种


          #EXTM3U
#EXT-X-VERSION:3
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-ALLOW-CACHE:YES
#EXT-X-TARGETDURATION:11
#EXT-X-KEY:METHOD=AES-128,URI="http://ogtoywd4d.bkt.clouddn.com/hls128.key",IV=0xb279c05ae6a3d0ffd45da748cf305dd9
#EXTINF:10.927589,
/58IzAY_GglrObBBbbD98wrHIbLk=/llhpmYRGVWfZL8dyCPXwCwKovI9R/000000.ts
#EXT-X-KEY:METHOD=AES-128,URI="http://ogtoywd4d.bkt.clouddn.com/hls128.key",IV=0x4aec782ea1419fb7865ba5452cbd9413
#EXTINF:9.342667,
/58IzAY_GglrObBBbbD98wrHIbLk=/llhpmYRGVWfZL8dyCPXwCwKovI9R/000001.ts
#EXT-X-KEY:METHOD=AES-128,URI="http://ogtoywd4d.bkt.clouddn.com/hls128.key",IV=0xeac1912aaab5469783cbb742b9f6f534
#EXTINF:10.719044,
/58IzAY_GglrObBBbbD98wrHIbLk=/llhpmYRGVWfZL8dyCPXwCwKovI9R/000002.ts
#EXT-X-KEY:METHOD=AES-128,URI="http://ogtoywd4d.bkt.clouddn.com/hls128.key",IV=0x500f42c7a7c969f47bd8886444c2d198
#EXTINF:9.342667,
/58IzAY_GglrObBBbbD98wrHIbLk=/llhpmYRGVWfZL8dyCPXwCwKovI9R/000003.ts
#EXT-X-KEY:METHOD=AES-128,URI="http://ogtoywd4d.bkt.clouddn.com/hls128.key",IV=0x9b1b6e27eb70eb32c164bb12cde89a86
#EXTINF:10.468789,
/58IzAY_GglrObBBbbD98wrHIbLk=/llhpmYRGVWfZL8dyCPXwCwKovI9R/000004.ts
#EXT-X-KEY:METHOD=AES-128,URI="http://ogtoywd4d.bkt.clouddn.com/hls128.key",IV=0x947eba85bbefb54f364ce99b0121fbde
#EXTINF:9.300967,
/58IzAY_GglrObBBbbD98wrHIbLk=/llhpmYRGVWfZL8dyCPXwCwKovI9R/000005.ts
#EXT-X-ENDLIST

          

这种格式可以很明显的看出比上一种多了#EXT-X-KEY:METHOD=AES-128,URI="http://ogtoywd4d.bkt.clouddn.com/hls128.key",IV=0xb279c05ae6a3d0ffd45da748cf305dd9这种内容,EXT-X-KEY是m3u8规定好的加密字段,如果包含这个字段,那么再访问ts视频之前会先去请求这个URI去获取一个密钥(key),再拿着这个key去访问ts视频才能播放。很明显,如果要做到不是谁都能看视频的话,那就得再这个获取key的URI上动手脚,不是自己人就不给你key。

搞懂了这部分就可以开始前端的工作了。先来看看hls的兼容性,既然是苹果出的方案,那么ios部分肯定是支持的,令人惊讶的是Edge的兼容性也很高。 HLS播放的兼容情况在2018的今天ios以及android移动端都原生支持hls加密播放了,这真是个好消息,正好这个项目又不需要做pc部分,那么直接用原生开撸就好了。


          <video id=video class="real-video" controls :poster='videoInfo.coverImageUrl'>
  <source :src="videoInfo.videoUrl" type="application/x-mpegURL">
</video>

          

现是使用上述第二种m3u8格式,但是URI未加鉴权直接返回key值的m3u8文件来测试。但是在调试的时候发现安卓没毛病,但是ios移动端无论如何都播放不了加密后的视频,这就有点头大了,这不是apple自己出的吗?怎么死活播不出来?调了半天播不出来,搜“HLS safari mobile”里面说的全是原生支持,但是我这里原生就是出不来。 原生不能播,那就用插件咯,用了hls.js、videojs7、video6.* + videojs-contrib-hls、ckplayer都没成功播放出来(也有可能是我姿势不对),弄了两天都没弄出个所以然来,去找后端负责视频切片加密的大佬,发现我们使用的m3u8不只是hls加密,而且还在这个基础上使用了rsa加密,让他把rsa加密去掉后,safari mobile使用原生video标签播放就啥问题都没了。然后……然后就去掉了rsa加密只使用hls加密了[捂脸哭],所以safari mobile播放hls加密+rsa加密文件还是没解决(路过的大佬有方法的话,求指教呀~)。

既然双端播放hls加密(没加鉴权)视频没问题的话,那就可以开始加上鉴权来进行测试了。 简单点说,鉴权其实就是在访问这个URI时,带上特定的cookie让后端来判断是否是合法用户,在我这个项目中,

  • 用户登陆是用test.abc.com的接口,
  • 项目是在m.abc.com上,
  • 视频是在video.def.com里,
  • m3u8中的URI是test.abc.com的接口,

非常混乱,但是除了视频地址,其余的都有一个统一的一级域名,所以在后端传cookie来的时候,domain可以改为.abc.com来匹配所有abc.com的二级域名。这个方案在ios部分是可行的,我所需要的user_tocken以及vidoe_ticket 在访问m3u8中URI时,都成功的被携带了过去,并且成功获取到了密钥(key)。 但是在安卓的webview中,不被允许有这样跨域的访问,URI的访问没有带上任何cookie,即便是将domain改为test.abc.com。这头痛的设定又让我试了几个视频框架,但是都没有处理好这个问题,最终选择了修改m3u8文件的URI为m.abc.com,然后再在nginx中进行代理,代理到test.abc.com上,一顿骚操作……终于能成功播放了。

整个项目使用的vue框架,想动态修改视频src时,想当然的写的:src="videoInfo.videoUrl",但是在实际操作中发现,即便动态的修改了src,但是视频依旧按照原来的链接播放的。其解决方法是:


          this.videoInfo = Object.assign(this.videoInfo, newVideo);
// this.$refs.realVideo.src = this.videoInfo.videoUrl
// this.$refs.realVideo.load()
document.querySelector("#video>source").src = this.videoInfo.videoUrl
document.querySelector("#video").load();

          

其实也可以使用vue的$refs属性而不是原生的dom操作。

好了,项目终于完整的跑通了……遇到的问题很多,还未解决的问题也很多,但是学到的东西也挺多的,嘿…… 这篇文章一定也有很多错误或者不够完善的地方,还望指出一同进步~~

SHOW

记一次使用sequelize

- OY欧阳 学习文章Mysql

现在已经做了两个个人网站的项目了,其中都有用到sequelize、sqlite3,但是两次使用下来还是不太熟练,所以再次记录下来,一是加深印象;二来要是再记不清楚,也不用再花太多时间来寻找解决方法了。

第一步:安装npm包

npm install sqlite3 --save-dev
npm install sequelize --save

第二步:创建一个model文件夹,在其中创建一个js文件,用来创建和操作数据库。

创建一个js文件来创建和控制数据库

第三步:进入teacherEssay.js文件

第四步:引入必要的模块,并且创建一个空白的数据库

let path = require('path')
let Sequelize = require('sequelize')

然后创建一个数据库,由于不是用的mysqlpostgresmssql等数据库,并且也不需要什么用户名什么的,所以就把那些东西全都省去了。

var sequelize = new Sequelize(undefined, undefined, undefined, {
  host: 'localhost',
  dialect: 'sqlite',
  storage: path.join(__dirname,'./database/teacherEssay.sqlite')
});//在你需要的地方,创建好这个database文件夹

sequelize
.authenticate()
.then(function(err) {
  console.log('Connection has been established successfully.');
})
.catch(function (err) {
  console.log('Unable to connect to the database:', err);
});

现在,保存文件,并且在命令行运行这个文件。

node teacherEssay.js

现在,在你的database文件夹下就多了一个teacherEssay.sqlite文件,这代表一个数据库就创好了。 创建好的数据库

到了这一步,上面的部分代码已经可以不要了,你可以注释掉或者直接删掉了,如下: 创建数据库完成后的代码

第五步:定义模型

虽然创建好了数据库,但是里面还是一片空白,所以现在还要定义模型。


          // 定义模型
var TeacherEssay = sequelize.define('teacherEssay', {
  EssayTitle:{
    type:Sequelize.STRING
  },
  EssayPreview:{
    type: Sequelize.STRING
  }
});

// 如果在TeacherEssay.sync()中写入force:true,
// 那么将在重新创建数据库之前删除原来的数据库
TeacherEssay.sync().then(function () {
  // Table created
  return TeacherEssay.create({
    EssayTitle: '欢迎来到数学乐园',
    EssayPreview: '这里是数学乐园',
  });
});

          

在定义数据类型的时候,可以参考 官方文档。 定义好模型,并创建了第一组数据后,可以通过下面的代码来检查一次是否创建成功。

TeacherEssay.findAll({raw:true}).then(function(essay){
  console.log(essay)
})

同样,如果都创建成功了,又有些代码可以不要了: 有些家伙要注释掉

第六步:引出模块

module.exports.TeacherEssay = TeacherEssay

至此,一个简单的数据库就弄好了。完整代码在这。 当然,这只是一个非常简单的数据库,如果想要进阶,可以多看看官方文档

SHOW