https://www.youtube.com/playlist?list=PLVAxjdyIU8_xVHCKW7bgAF7VaTSqC4p_1
主持人首先欢迎观众观看2023年web黑客世界舞蹈大赛的决赛。回顾2022年的决赛,人类选手锚和AI选手Iris进行了激烈的较量。锚表现不佳而输给了Iris。
locks前年失利后一直在MIT的开放课程学习训练自己。此次他力求改变去年的结果。
Iris是苹果公司研发的AI,具有强大的计算能力。它在过去的比赛中表现出色。
两位选手表示将以友好的态度来进行比赛,不再让技术差异成为分歧。他们决定联手合作,共同提升舞蹈水平。
主持人感谢两位选手携手同行的良好表示,并宣布2023年web黑客世界舞蹈大赛正式展开。
本次课程将从后端到前端教授全栈网页开发。
第一周将教授网页开发的基础知识,如搭建一个简单的demo网页。
第二周将加入一些高级主题和赞助商演讲。
第三周给予学习时间,可以在学习活动和策划师助下开发自己的项目。
第四周给予学习时间,希望能完成项目。
视频课将上传YouTube直播并录制。
每次课后都有现场问答。
课后将组织工作坊学习活动。
提供帮助队列实时帮助学习。
Piazza论坛上公布信息和链接。
课程不强制出勤,但提供免费午餐吸引学生参与。
第零次作业:提交10个项目想法。
项目提案:完善选定项目并安排演示时间。
最少可行产品:实验性实现产品核心功能。
最后产品:完成产品所有功能与除Bug。
必须是动态网站,根据用户操作有不同功能。
需后端支持,有个人账户体系。
不能只是静态页面,至少包含两个不同页面。
尽可能创新并解决实际问题。
官网:weblab.mit.edu
课程信息:weblab.mit.edu/schedule
演示网站:weblab.example
Piazza论坛
BucaBuca工程问答网站
版本控制系统可以追踪文件的修改历史,它允许将代码分成不同的版本,可以随时复原到之前的版本。
常见的版本控制系统有CVS、Subversion、Git等。
Git是分布式版本控制系统,每个人的工作区都是一个完整的Git项目仓库,同时每个人又可以与中央仓库(比如GitHub)同步。
Github是一个程序开发平台,它提供git版本控制系统的远程仓库服务。开发者可以将本地仓库与Github远程仓库同步,实现多人协作。
版本控制系统可以管理代码文件的修改历史,开发者可以随时从远程仓库获取最新的代码。
开发者在各自的本地仓库修改代码后,可以很方便地将修改同步至远程仓库,实现多人协作开发。
如果代码有问题,可以随时回退至之前的可靠版本。
工作区:本地的文件目录
暂存区:将修改后的文件暂存到这里
本地仓库:本地git项目的仓库
远程仓库:例如GitHub上的仓库
版本(commit):一次文件的修改提交,形成一个版本
分支(branch):同一份代码的不同开发线
拉取(pull):从远程获取最新修改
推送(push):将本地修改推送至远程
初始化本地仓库 git init
添加暂存区 git add
提交commit git commit
推送至远程仓库 git push
拉取远程仓库修改 git pull
解决冲突处理文件合并
分支操作创建与合并分支
本节介绍了版本控制系统Git的概念及基本应用流程。Git可以有效解决代码同步、版本管理和多人协作问题。使用Git需要明确工作区、暂存区、本地仓库和远程仓库的概念,熟悉基本命令比如add、commit、push、pull等。
Git是一个版本控制系统。它能够跟踪代码文档中的变更记录,从而实时协同多个开发人员开发同一个项目。
版本记录。Git可以记录每次代码变更,方便开发人员回退到以前版本。
实时协同。开发人员可以在本地工作,然后上传最新代码到中心Git服务器。其他人员即可拉取最新代码,保证每个人都在工作同一个代码库最新版本。
合并冲突。如果多个人同时修改同一个文件,会产生冲突。Git可以检测出冲突部分,开发人员需要手动修改解决冲突。
本地开发。每个人都可以在本地单独开发,不影响其他人工作,等开发完成后再上传中心服务器。
仓库:一个项目的所有Git管理的文件组成一个仓库。
版本(commit):一次具体的文件修改操作提交到仓库形成一个版本。
日志:仓库所有版本的记录,即所有commit的历史记录。
推送(push):将本地仓库的新版本提交到远程服务器仓库。
拉取(pull):从远程服务器仓库获取最新版本到本地仓库。
Github是最流行的Git远程仓库服务器,可供开发人员免费使用。开发人员可以将本地Git仓库推送到Github作为备份,其他人员也可以从Github拉取代码。这样就实现了代码实时协同的目的。
HTML(超文本标记语言)是一种用来描述网页结构的语言。它描述网页的各个组成部分及其相互关系,但不决定页面内容的样式和布局。
CSS(级联式样式表)用来描述HTML元素如何在浏览器中显示,决定元素的字体、颜色、大小、位置等排版样式。
HTML文档包含<html>
根元素,其中包含<head>
和<body>
两个主要元素:
<head>
包含页面的元数据,如文档标题<title>
等。<body>
包含文档的可见内容,如段落<p>
、标题<h1>
等。HTML文档通过元素的开闭标签来描述页面的结构层次,元素可以相互嵌套形成父子关系。
常见HTML元素包括:
<h1> - <h6>
<p>
<a>
<img>
<div>
和Span元素<span>
不同元素对内容的格式有默认样式,但可以通过CSS进行重定义。
属性用来修改HTML元素,常见属性包括:
<a>
元素的href属性,用于给出链接地址<img>
元素的src属性,用于指定图像源文件属性名和属性值使用名称=“值”的形式定义在元素内。
HTML文档需要在<html>
元素之前添加<!DOCTYPE html>
声明,表明文档遵循HTML5规范。
元素采用成对的开始标签和结束标签来定义范围,单标签元素只有开始标签。
以上就是HTML与CSS基础知识的简要概述。后续将详细介绍不同元素的使用及CSS样式规则。
HTML标签有<h1>
到<h6>
用于标题,<p>
用于段落,<div>
用于划分区域。
<img>
标签用于在网页中显示图片。
<a>
标签定义锚超链接,可以用来跳转到其他网页或图片。
<hr>
标签定义水平线。
CSS用于控制HTML元素的样式,如文字颜色、大小、间距等。
CSS规则由选择器和声明建构而成。选择器指向HTML元素,声明用来设置相应样式属性的值。
本次工作项目是一个简单的社交网站“猫书”,将按步骤实现其主要界面结构和样式。
第一步是通过HTML结构搭建基本骨架,添加标题、段落、图片等元素。
第二步是通过CSS对各个元素进行样式控制,设置颜色、字号、间距等属性。
最后将逐步实现猫书主页效果图所示整体界面布局。
本次工作主要使用HTML与CSS进行前端开发。
编辑器使用Visual Studio Code。
源代码存储在GitHub代码仓库中,使用Git命令行进行版本控制。
预览效果直接在浏览器中打开HTML文件。
如果在安装或使用开发工具过程中遇到问题,可抬手或者在线下求助工作人员解决。
用户界面(UI)指网站的单个部分,如颜色、字体、布局等。用户体验(UX)指用户与网站交互时的体验,如响应时间、导航性能等。
设计样式会经历多次迭代。初版可能直接用纸版简图,但随着不断优化,设计会越来越成熟。通过多个版本的迭代给用户带来更好的体验。
网站设计应适用于不同屏幕尺寸,如手机和笔记本电脑。如果不做响应式设计,不同设备上浏览体验将不一致。可通过在手机和缩小浏览器窗口查看设计效果,使用inspect元素工具检查响应性。
以登录表单为例,通过添加背景颜色,阴影,圆角,边距等细节处理,可以将一个简单的表单组件设计得更友好易用。
不同时期的设计风格会有所不同。早期重现现实感,现在趋向简洁平面。应关注设计潮流变化,让站点设计看起来更时尚前卫。
好的用户体验重视用户在产品交互时的实际感受,而不是外观。应将重点放在如何让用户更顺畅方便地完成任务。
JavaScript是一种脚本语言,可以动态操作网页内容。它可以响应用户在页面上的操作,可以使网页具有交互性。
JavaScript与Java语言虽有相似之处,但实际上两个语言没有直接关系。JavaScript主要运行在浏览器端,用于网页交互。
导入JavaScript的方法是在HTML文档的<head>
中使用<script>
标签引入外部JavaScript文件。
JavaScript有5种基础数据类型:
用let
、const
和var
来定义变量。
let
:用于定义变量,变量值可以改变const
:用于定义常量,常量值不能改变var
:不建议使用,与let作用相同但存在一些差异变量命名应遵循驼峰式写法。
JavaScript语法包含:
使用console.log()
函数输出值到控制台进行调试。
使用alert()
函数弹出JavaScript对话框显示信息。
数组用[]
定义,使用索引从0开始访问数组元素。
数组可以包含不同类型的数据。
函数使用function
关键字定义。
函数可以接收参数,返回值。
使用//
书写函数注释解释函数功能和用法。
以上内容总结了JavaScript的基本概念,数据类型,变量,运算符,语法规则以及数组和函数的定义与使用方法。
这个游戏使用setInterval方法每隔一定时间调用主函数main,更新游戏状态。为了方便修改游戏速度,定义一个snakeSpeed变量存储更新频率。
const snakeSpeed = 200;
setInterval(main, snakeSpeed);
使用数组snakeBody存储蛇身各节的坐标点。坐标点使用对象表示,包含x和y属性。
初始化时,蛇身有3节,位置在棋盘中间,y坐标从11至9。
const snakeBody = [
{x: 11, y: 11},
{x: 11, y: 10},
{x: 11, y: 9}
];
每一帧需要删除蛇尾增加蛇头,更新蛇身位置。
删除尾部使用数组的pop方法。
增加新头部,定义新的坐标点对象加入数组第一个元素。
function updateSnake() {
snakeBody.pop();
const newHead = {
x: snakeBody[0].x,
y: snakeBody[0].y
}
snakeBody.unshift(newHead);
}
这个工作坊的目标是使用JavaScript来实现贪吃蛇游戏。通过定义变量和数据结构来表示游戏状态,利用定时调用的方式来连续更新状态并渲染游戏画面,实现基本的游戏逻辑。
在game.js中添加布尔类型的gameOver变量,默认为false。
在主循环函数main中,检查gameOver变量值。如果为true,则弹出提示”Game Over”,并清除定时器停止循环。
在更新函数update中,调用函数isGameOver判断是否结束。如果结束,将gameOver置为true。
isGameOver函数返回布尔值,用于判断是否结束的条件有:
用或运算符 | 表示任一条件满足则返回true。 |
提供snakeOutOfBounds和snakeIntersectsItself两个函数判断具体条件,定义在snakeUtils文件中。
运行游戏后,可以正常吃食增加身体,但撞墙或自身结束游戏,弹出提示并停止循环。完成基本贪吃蛇游戏逻辑。
React是一个用于构建用户界面(UI)的JavaScript库。它可以让我们将网站划分成多个独立的、可复用的组件来构建。
组件实际上就是一个自定义的HTML标签。它以大写字母开头,用来封装一些界面元素。应用程序可以根据组件来进行划分。
组件接收外部数据作为属性。属性是不可变的,不能直接修改。组件通过状态来保存内部变化的数据。状态只在组件内部可见,不会影响其他组件。
父组件通过属性向子组件传递数据。子组件无法修改父组件的属性,但是可以通过调用回调函数来通知父组件进行操作。
使用React开发网站时,会先定义顶层组件App,然后将App下分解为子组件,如导航栏Navbar、Feed等。这些组件再可以包含更小的子组件,层层下掘。
可以通过打印组件树结构来记录组件的层级关系。这对理解网站结构和数据流向非常重要。
Post组件可以保存所有评论作为其状态。Post会通过属性向Comment组件传递必要数据。Comment组件可以单独保存状态如点赞数。
组件之间依赖关系遵循父子传值的模式。这实现了数据的单向流动,避免互相干扰,有利于开发和维护。
在Figma中,我们可以创建元素、帧和组件。
元素是图形、文本或者其他可视内容。它们可以放在帧或者组件中。
帧代表不同的视口,如手机、平板或电脑。它们用来组织和展示元素。常见的有手机、平板、MacBook等预设帧形式。
组件代表可重复使用的模块,如按钮、卡片或布局。我们可以通过拖拽复制组件来实例化它。
Figma是一款流行的原型设计工具。它支持向量 graphics,可以通过添加帧、元素、组件高效设计交互式原型。组件功能可以提高工作效率。原型功能可以测试用户体验流程。
在React中,我们把整个网站视为一个大型组件,称为App组件。我们可以将App组件根据需要分解为任意多个更小的组件。
组件可以接收数据作为属性(props),也可以保存内部状态(state)。props是父组件向子组件传递的数据,state是组件内部自身管理和更新的数据。
可以使用组件树来表示App,将App组件划分为各级子组件。在组件树中,props标记在箭头上表示从父组件到子组件的传递,state包含在组件框内表示组件内部状态。
将上一天用HTML+CSS创建的Cardbook网站改写为React版本。点击图片后,可以增加“猫咪快乐值”状态变量,实现响应式互动效果。
至此,使用React将Cardbook网站重构为组件结构,并实现了点赞交互效果。掌握了React组件的概念及基本使用方法。
过去几天我们学习了HTML和CSS来制作页面,但是页面内容始终不变,没有使用用户数据。原因是还没有学习后端,也就是数据储存和处理的那一部分。
前端是用户直接交互的部分,后端是 unseen 的部分,负责数据的储存、处理和其他后台操作。
客户端(浏览器)和服务器通过请求与响应进行通信。
每次客户端需要从服务器获取信息时,会发送一个请求给服务器。服务器收到请求后,会发送一个响应回来。
常见的请求方法有GET和POST。GET用于获取数据,POST用于创建或修改数据。
HTTP(超文本传输协议)用于客户端和服务器之间的数据传输。
HTTP请求包含:
HTTP响应包含:
API(应用程序接口)是允许其他系统访问某个系统的方法的集合,通过它可以访问开放数据的结构化访问点。
例如社交网站提供API让其他开发者访问部分功能。
常见API终点有:/comments获取评论数据,/comment发布评论等。不同方法(GET/POST)对应不同操作。
开发者可以通过浏览器开发者工具中的网络面板,查看网页请求所调用的API,获取更多信息。
get请求获取数据,post请求上传数据或创建新数据
客户端是浏览器,服务端可能部署在任何地方,但一般会在服务器上。
服务器之间也可通过HTTP请求交互。
组件可以嵌套组成组件树,组件树是对组件的层次关系的抽象。一个Web应用中的每个组件都可以看成是一个节点,组件之间形成父子关系。
将一个大组件拆分为多个小组件,可以避免代码变得过长难以阅读。
如果一个页面有独立的部分,且这些部分间没有交互,那么它们可以拆分为独立的组件。
使用组件树可以更好地控制应用各部分之间的信息流通,防止错误变量的使用和其他副作用。
Props是从父组件向子组件传递数据的一种方式,是单向下行传递的。
Props的传递应该根据组件的实际需求,例如Tweet组件需要postId来显示对应评论和点赞。
State用于保存组件内部交互性数据的变化,不能直接修改但通过useState可以初始化和同步修改。
使用useState函数初始化状态变量,后续修改需要使用自动生成的setter函数,不要直接赋值修改。
修改State是异步的,因此读取状态数据时不能确定当前值。
使用React开发应用时,应将UI划分为组件树,根据实际需求合理拆分组件;利用Props实现组件间的通信;使用State管理组件内部可变状态,结合useState提升组件响应性能。
Feed页面包含:
提交新帖子:/api/stories (POST)
根据获取的数据渲染Feed页面
获取更新后数据重新渲染
根据数据渲染帖子详情及评论区
在这节课中,主要讨论如何在React应用中添加路由功能。
首先需要导入Reach Router库:
import { Router } from '@reach/router';
定义FeedPage、ProfilePage和NotFoundPage组件,并通过path属性指定每个组件对应的路由路径。
<FeedPage path="/" />
<ProfilePage path="/profile" />
<NotFoundPage default/>
通过Router组件包裹三个页面组件,以实现不同路径对应的路由渲染。
<Router>
<FeedPage path="/" />
<ProfilePage path="/profile" />
<NotFoundPage default />
</Router>
创建Navbar组件,使用Link组件生成可点击链接,对应不同页面路径。
<Link to="/">Home</Link>
<Link to="/profile">Profile</Link>
通过CSS给导航菜单链接设置样式,例如内边距、颜色等。
到此,一个简单的React路由功能就完成了,可以基于URL渲染不同页面,并通过导航菜单实现页面切换。
JavaScript允许使用异步操作,这意味着多个过程可以同时运行,而不会阻塞其他代码。使用Promise对象可以将异步操作进行封装。
Promise有三种状态: fulfilled(已成功)、 rejected(已失败)和pending(未完成)。使用.then()方法指定resolved状态的回调函数,.catch()方法指定rejected状态的回调函数。
Promise常用于网络请求、IO操作等需要一定时间的操作。例如使用Promise调用API,可以在等待响应时执行其他任务,而不阻塞整个脚本。
Promise也可以串联执行,第一个Promise返回Promise对象,可以在.then()中返回第二个Promise,以执行后续操作。这种方式可以实现任务链的效果。
如果有多个Promise,可以使用Promise.all()同时等待它们完成,并返回结果数组。Promise.race()可以等待第一个完成的Promise结果。
异步函数是会返回控制流但计算未完成的函数。它通过async关键字标识,内部可以使用await关键字暂停函数执行直到Promise完成。
定义异步函数时加上async关键字。await仅在异步函数中有效,它等待Promise完成后才继续执行下面的语句,可以将Promise值直接赋给变量。
相比Promise层层嵌套的写法,async/await实现了同步操作的语法,更直观简洁地表达异步流程。
服务器是任何客户端(如个人计算机或手机)与之交互以获取或存储更多信息的事物。客户端通常通过请求与服务器进行通信,服务器会返回响应。
服务器通常用于文件访问控制、 centralized数据存储和安全认证。每个计算机都可以运行服务器代码。
计算机可以同时运行多个进程。服务器可以绑定到特定的网络端口来区分不同服务,比如3000端口或5050端口。常用端口有443(HTTPS)。
当浏览器访问网站时,不必指定端口,因为浏览器默认知道要使用哪个端口。但在游戏中,不同游戏可能使用不同端口。
常见服务器语言有Python、Java、Express以及JavaScript。在本课程中,我们将使用Node.js来运行 Express框架,构建基于JavaScript的服务器。
Node.js是一个JavaScript运行时环境,可以用于运行服务器端JavaScript代码。
npm(Node Package Manager)用于管理Node项目依赖。每个Node项目都有一个package.json文件来定义项目元数据和依赖库。npm install会安装package.json中定义的依赖项。
Express是一个基于Node.js的Web应用程序框架,用于快速开发Web应用和API。使用Express可以定义HTTP请求方法、请求路由和回调函数。
比如,app.get(‘/api/test’, function(req, res) { res.send(‘First API’) }) 定义了一个GET请求路由。
要防止单个错误抛掉整个服务器,可以使用error handling中间件。比如app.use(function(err, req, res, next) { res.status(500).send(‘Error!’)}) 处理服务器内部错误。
本节介绍了服务器相关概念,如网络端口、服务器语言、Node.js与npm的使用。最后介绍了如何使用Express框架快速构建API路由,以及错误处理机制。
API(应用编程接口)是一种让独立的软件系统之间进行交互的方式。在本次工作坊中,我们将使用Express框架来搭建一个API,使用Express自带的Router模块来分离API的不同端点。
Router模块可以将API的不同功能点隔离开来,使得API结构更加清晰易懂。我们可以给Router起名为api,这样所有的API请求都需要以/api开头。
在api.js中使用express.Router()方法创建一个Router实例。
将Router导出模块,让server.js可以导入使用。
在server.js中导入api.Router,并使用app.use()方法告诉程序我们的API存在,以/api开头的请求都需要使用这个Router处理。
为了测试API,我们先添加一个简单的/test端点。
我们需要向API中添加数据。我们通过在api.js中定义一个data对象模拟数据,对象中包含stories和comments两个属性,每个属性值为一个数组,数组内包含描述故事或评论的对象。
为stories添加一个get请求端点,通过res.json()方法将data.stories数据返回。
使用req(请求对象)和res(响应对象)可以获取请求信息和返回响应。req.query用于获取GET请求参数,req.body用于获取POST请求体数据。
res可以设置响应状态码和发送响应体数据。
按照同样的流程可以继续添加其他API功能点。
以上就是初步搭建和使用一个basic API的基础知识。后续会学习数据库的使用,不再需要硬编码数据。
HTML用来组织和定义网页的结构及内容。
CSS用来控制网页的外观和样式,如字体、色彩和布局。
JavaScript用来控制网页的交互行为和动态效果,比如点击按钮时弹出窗口。
React允许使用组件的概念将代码结构化。
顶层组件App包含子组件Theme、Profile、Navbar。
Feed组件包含Card和LinkPosts子组件。
组件可以重复使用,如 Feed 中可以包含多个 Card。
useState Hook可以让函数组件也可以有状态。
useState返回一个状态值和更新状态的函数。
使用setState函数而不是赋值,可以通知React重新渲染UI。
状态变量在组件重新渲染时会保留值。
useEffect可以用于在组件装载和卸载时运行副作用。
第一个参数是要执行的函数,第二个参数是一个空依赖数组。
此时只会在首次加载时执行一次函数。
服务器是运行在计算机上的代码,提供客户端服务。
客户端向服务器发出请求,服务器返回响应数据。
服务器可以用来存储和访问大量数据、保护中心数据源等。
HTTP定义了客户端和服务器间通信的格式和语义。
常用的方法有GET请求获取资源,POST创建新资源。
通常用HTTP与API交互。
前端和后端之间的关系
用户通过浏览器(前端)访问网站,看到的页面内容是前端代码(如React组件、HTML、CSS等)渲染出来的。
前端主要负责页面展示与用户交互,但不负责获取数据。当用户输入信息时,前端将数据发送到后端。
后端在后台运行,负责处理前端发送来的数据,并向前端提供服务。例如保存用户输入到数据库,或从数据库获取数据返回给前端。
前后端通过HTTP请求与响应来通讯,主要有GET请求和POST请求两种。
GET请求通过地址参数指定需要获取的数据;后端从数据库或其他来源获取数据返回给前端。
POST请求通过请求体发送新数据到后端;后端接收数据后处理,如保存到数据库,并不需要返回数据给前端。
API设计
API endpoint用来定义某个服务的URL地址及其处理请求和响应的方式。
GET请求指定endpoint详细输入(查询参数)和输出(响应格式);POST请求指定endpoint要求的输入格式和数据类型。
前端作为API的客户端向后端发出请求;后端提供API服务,定义输入输出规格与处理逻辑。
后端内部也可以调用其他外部API,此时后端成为客户端,外部API提供者是服务器。
Cathook API设计
Cathook后端提供STORIES、COMMENTS等5个endpoint服务前端请求,其中:
GET /api/stories 获取所有故事
GET /api/comments?parent=id 根据ID获取某个故事下的所有评论
前端使用fetch方法调用对应endpoint。后端根据请求参数从数据库或内存中查询数据返回给前端。
数据库存储与操作数据
后端通常通过数据库持久化存储数据。数据库能高效存储和管理来自不同用户和服务的大量数据,后端通过数据库操作来读取、新增和更新各种数据信息。
本节课将使用数据库将前端与后端连接起来。课程将进行以下步骤:
将后端服务器与数据库连接起来。
创建评论和帖子模型(使用Mongoose)。
修改API端点,使用Mongoose模型。
与workshop 3相似,老师将一步步进行解释。学生可以自己跟着实现。
对于Mongoose不熟悉的同学,可以参考redrock.is/mongo.snippets看一个Mongoose常用命令小抄。
MongoDB是一种基于文档的数据库管理系统。它允许将数据存储在 flexible的文档中。
Mongoose提供了一个对象模型(object modeling tool)来工作与MongoDB。它可以与Node.js一起使用来访问MongoDB数据库。
要使用Mongoose与MongoDB进行交互,需要创建模型。模型定义了如何与集合内的文档交互。
const mongoose = require('mongoose');
使用mongoose.Schema()
定义一个Schema,指定每个字段的数据类型:
const schemaName = new mongoose.Schema({
field1: String,
field2: Number
});
使用mongoose.model()
创建Model,并指定使用的集合名称。
使用module.exports
导出Model供其他文件使用:
const ModelName = mongoose.model('CollectionName', schemaName);
module.exports = ModelName;
使用定义好的Model可以对MongoDB数据库进行CRUD(Create, Read, Update, Delete)操作。
使用Mongoose可以很方便地在Node.js应用中的API中访问MongoDB数据库。先导入模型,再在路由处理程序中使用模型的静态方法进行操作。
例如,创建新文档:
ModelName.create({name: 'John'})
读取全部文档:
ModelName.find({})
等等。通过Mongoose可以方便地在API中操作MongoDB数据库。
web应用需要用户账户,用户每次操作不可能都要重复登录。有两种方式实现认证的持久化:
应用程序不应直接存放用户明文密码。可以采用加密哈希存储密码的散列值。
指通过第三方账号如微博、GitHub登录。第三方网站充当验证角色,用户不需要在每个网站都注册账号。
以上就是账户认证的主要知识点。会话和令牌两种方式都可以实现认证信息的持久化。应用中不应直接暴露敏感数据,需要采取相应的安全策略。
HTML、CSS、JavaScript是三大主要的Web开发语言:
React是一个JavaScript库,用于在前端构建用户界面:
组件从被加载到页面到消失的过程包括以下阶段:
组件生命周期中提供了多种方法供开发者插入自定义逻辑代码。
使用React开发时:
这提供了一种高效灵活的方式组织界面的构建。
React应用可以看作是一个组件树结构,各个组件代表应用不同的部分。
本次Chatbook应用中的主要组件包括:
为了展示和交互数据,组件需要使用属性和状态管理数据。
Chatbook组件需要管理:
Message对象包含:
User对象包含:
后端需要实现以下两个接口:
首先实现最基础的NewMessage和SingleMessage组件:
以检查基础交互是否正常,后续添加后端交互代码。
在聊天界面组件chatbook.js
中,现有消息数据通过常量直接传入,不会根据后台更新变化。
我们添加状态activeChat
管理当前聊天,包含recipient
(接收对象)和messages
(消息列表)两个字段。
定义状态时使用useState
Hook,传入初始值对象。
新增状态后,需要将其传递给子组件。直接将activeChat
状态传递即可,组件结构和渲染不变。
这样一来,一旦activeChat
状态更新,子组件也会自动重新渲染。
新建message.js
定义消息Schema,包含sender
(发送对象)、recipient
(接收对象)、timestamp
(时间戳)、content
(内容)四个字段。
在api.js
中定义post /message
接口路由,要求登录验证。
首先打印接收到的消息,便于调试。然后新建消息对象,从请求参数中获取recipient
和content
,sender
直接从登录用户获取。
将消息对象保存到数据库即完成一条新消息的添加。
本次学习实现了前后端的基础交互功能:
后续可以添加获取历史消息与更新界面等功能完善产品。
良好的编码实践可以提高代码的可读性,节省时间。开发人员可以更好地理解自己的代码,也更容易与其他人合作。代码的调试 frequency 会下降,编码的过程变得更加有趣和容易。对于从事编码工作的专业人员来说,掌握良好的编码标准关系到是否通过面试和是否能拿到工作机会,也影响工资和晋升空间。
获取其他人最近commit的代码,以避免冲突。使用git status
和git diff
查看自己本地的改动情况,以免提交不必要的文件。
代码改动应该精焦小而频繁。每次只加入相关的修改,不要添加过多代码在一个commit里。commit信息应该清晰且格式一致,避免使用否定语气。
git push --force
会忽略冲突直接覆盖远程分支,很容易破坏其他人的工作,应谨慎使用。不应提交含错误的代码。
掌握良好的编码实践对开发人员职业发展和项目合作都很重要。需要注意代码质量和他人成本,避免 waist时间。
这场演讲主要介绍了Vividly公司用来解决供应链中的促销活动管理问题的技术方案。
许多品牌在杂货店或在线销售渠道每年都会开展数百或上千个促销活动。这给品牌带来一些问题:
哪些产品需要促销?广告时机如何定?
活动规模大小如何决定,如单品卡券还是线下优惠?
活动开展范围在哪些店铺?
活动持续时间长短如何安排?
活动何时开始何时结束?
Vividly使用以下技术来解决品牌的促销活动管理问题:
建立客户(品牌)、产品、促销活动三个数据模型之间的关系图来描述data之间的关系;
提供不同的数据视图接口,如获取所有客户ID列表、单独产品数据模型、客户与产品的关系等;
考虑数据适应性、性能和授权等多方面因素设计数据获取接口;
使用GraphQL这样的技术架构,实现动态和按需获取数据的能力。
举例介绍了一个CBD客户WebLab的使用案例:
WebLab有多个客户,提供几十种产品,定期开展促销活动;
使用Vividly技术可以实现查看客户列表,单独产品信息,客户与产品关系等复杂数据视图;
帮助WebLab更好地管理客户,产品,活动数据及其之间的关系。
总体来看,Vividly利用技术,通过数据集成和接口设计的方式,有效解决了品牌在促销活动管理中的数据获取、管控等问题,助力品牌运营工作。
本课将讨论使用网络套接字实现实时聊天软件。使用HTTP请求实现的聊天需定期刷新页面才能查看新消息,体验不佳。网络套接字可以让服务器主动推送消息给客户端,实现实时通信。
客户端可以不断地发GET请求询问是否有新消息。但是这种方式性能不佳,客户端需要频繁请求,服务器也需要处理更多请求。
WebSocket允许服务器主动推送消息给客户端。客户端可以从其协议层级升级普通连接为WebSocket连接,从而实现双向实时通信。
Socket.io库是基于WebSocket协议实现的JavaScript实时通信库。它可以隐藏底层WebSocket实现细节,使用emit()和on()简化代码。
服务端使用SocketManager管理所有Socket连接。emit()方法广播消息给所有客户端。
客户端使用on()监听 specific事件,调用注册的回调函数处理消息。回调函数内实现页面更新等动作。
一个教师发布作业的场景:服务端使用emit(“newPset”,数据)广播;客户端使用on(“newPset”, cb)监听, cb内开始工作。
总之,通过Socket.io优化HTTP,服务端可以主动推送消息给客户端,实现实时通信和信息同步。
在聊天列表中点击某个用户时,应更新左侧显示的活动用户以及右侧显示的消息内容。
具体操作:
设置活动用户的聊天内容为点击用户,同时清空消息内容。
考虑优化:检查当前活动用户与点击用户是否相同,若相同则无需重复操作。
使用 useEffect 钩子更新消息历史,并把加载消息历史的函数加入依赖项数组中。
加载指定聊天的消息,而不是加载所有聊天的消息。
原先API在查询消息时,硬编码使用了”allchat”作为接受者ID。
现改为:
定义查询语句query。
如果查询值为”allchat”,则使用原语句。
否则,使用mongdb特殊查询语句$or,设置两种条件:
发送者为自己,接收者为对方
发送者为对方,接收者为自己
返回符合任一条件的消息数据
原来私聊消息使用getIO广播给所有用户,应单独发送给接收者。
修改API:
如果接收者为”allchat”,使用原方法广播消息
否则,使用getSocketsFromUserID方法,将消息发送给接收者和自己
以上实现了查看不同用户聊天、按用户过滤私聊消息等功能。
TypeScript是一种开源的编程语言,它是JavaScript的一个超集,增加了可选的静态类型和基于类的面向对象编程。
TypeScript主要做到以下几点:
为JavaScript添加类型检查功能,可以捕获许多程序错误;
兼容JavaScript所有语法,TypeScript代码可以直接编译成JS执行;
通过类型定义文件支持对现有JavaScript库的扩展,比如jQuery。
TypeScript是JavaScript的超集,包含了JavaScript所有的语法特性;
TypeScript会在编译阶段对代码进行静态类型检查并报错,但不会影响代码运行;
TypeScript会编译成正常的JavaScript代码,所以能在任何支持JavaScript的环境正常运行;
TypeScript增加了类、模块、接口等概念,但这些额外语法都不增加运行时开销,仅用于编译阶段类型检查。
使用let/var
加上类型定义来定义变量类型,例如let name: string = 'Jack';
可以根据初值类型进行类型推断,例如let age = 18;
会推断age为number类型
定义函数参数和返回值类型,为函数添加契约
使用接口来定义强制对象包含的成员
定义类并给类的属性和方法添加类型
枚举用于定义一组常量名称
原始数据类型包括数字、字符串、布尔值等
任意类型允许变量接收任意类型的值
void类型代表没有任何返回值的函数
undefined和null两种空值类型
可选参数和属性可以为空
非空断言操作(!/)可以忽略null/undefined检查
空值合并运算符(??)可以设置空值的默认值
定义接口描述对象形状,并约束实现它的类型
类实现接口来描述类的功能
函数类型描述函数参数和返回值形状
通用类型可以声明更广泛的类型
枚举可以完整枚举可能的值
模块通过对外export和import管理代码 uncoupling
TypeScript通过为JavaScript添加了类型系统和支持类的语法,使JavaScript成为一种可以进行大型项目开发的语言。它既可以享受动态语言的开发体验,又可以利用静态类型检查发现并修复问题。
HTML元素可以看作一个“盒子”,包含:
Flexbox可以方便地实现项目的排列。
参考代码:
<div class="container">
<div class="item">...</div>
<div class="item">...</div>
</div>
.container {
display: flex;
}
设计前应考虑用户的视角,了解用户需要看到什么内容,使用什么功能。这对任何项目都很重要。
用户体验要考虑用户看到的内容和使用的功能,这通常称为用户体验设计。用户界面是用户与页面交互的实体界面。两者关系很紧密。
包括字体、格式设计等,可传达不同风格。比如轻松欢快字体适用于儿童互动,严肃字体适用于医疗信息传达。
不同视觉素材可传达不同感觉。比如冥想APP采用自然景色和简洁设计传达宁静。社交APP采用鲜艳色调和动画设计传达活泼。
视觉外的音频设计也很重要,如光剑碰撞声增强星战场面的没真实感。界面交互声也能提升用户体验。
给产品编制统一的样式和主题,如颜色、图标风格,能传达品牌形象。比如平面设计网站采用简洁风格,游戏网站采用流光灵动风格。
考虑用户可能的使用流程,如搜索特定内容或浏览热门内容。给用户便利的交互方式。
确保界面元素如按钮点击明显且功能明确,让用户易于使用。
在开发产品时,需要了解用户的真实需求。
需求可以分为用户想要的(需求)和用户实际需要的(需要)两种。用户想要的可能只停留在特性层面,而不是产品在解决什么问题。
系统工程中将用户需求分类为功能需求和性能需求。功能需求指明产品必须提供的功能,比如登录系统、动态内容、数据库等。性能需求则描述产品如何工作,比如速度、可靠性等。
在有限开发时间内,需要选择哪些功能优先实现。可以通过用户访谈找出哪些功能对用户影响最大。
用户访谈的目的是了解用户的真实体验和需求,以确定产品设计方向。
可以考虑以下问题:
用户使用现有产品时遇到什么问题?
用户在什么场景下使用产品?使用频率如何?
用户最喜欢和不喜欢产品的什么功能?
产品可以帮助解决用户什么样的需求?
用户期望产品带来什么样的体验和价值?
访谈后需要总结用户的共同点和不同点,协助产品决策。访谈对象建议6人左右。
深入理解用户第一印象背后的原因
将视角从特性转移到用户需求
了解用户想要和实际需要的区别
基于用户需求选择产品方向和重点功能
用户研究的目的在于用户中心,不是产品或技术中心,从而开发真正解决用户问题的产品。
上坊介绍了分布式与中心化的概念。分布式的特点是:
以公共布告栏为例,每个参与者都会保存所有的交易记录。但是,如果参与者保存的数据不同,就可能出现双花问题。
为了解决数据不一致的问题,需要采用共识机制来使所有参与者达成一致。比如采用投票的方式来确认每一笔交易的有效性。
但是,共识机制本身也面临一些困难:
比特币采用了工作量证明机制来解决这些问题:
通过这个机制,比特币实现了分布式帐本的更新和维护而不存在单点故障,解决了双花攻击问题。
比特币 laid奠定了分布式账本的基础。随后,更多的数字资产应运而生,例如以太坊引入了智能合约功能,使得可以在区块链上发行和交易各种数字资产token。
NFT则利用了区块链的不可篡改性,可以唯一标识和跟踪数字资产的所有权,从而应用于艺术、体育等领域。
总之,区块链技术赋予了数字世界独一无二的属性,极大促进了 decentralization的发展。
游戏与之前制作的内容存在明显差异:
游戏逻辑与状态更复杂,需要同步多个玩家的状态和交互。
图形要求更高,需要实时渲染动画效果才能正常游戏。
HTML Canvas 是内置于HTML中的绘图区域,无需外部库即可使用。它可以高频率绘制屏幕,从而实现动画效果。
游戏只需要一个组件即可。大部分逻辑都在服务器端进行。
客户端用于输入处理和渲染。输入通过Socket发往服务器,服务器处理后回传游戏状态给客户端渲染。
游戏状态记录了所有需要同步的信息,如玩家列表、位置、大小等。它作为一个对象包装所有数据,服务器处理后通过Socket发送给客户端。
模仿Agar.io,使用Canvas在浏览器中实现类似游戏。
玩家用箭头键移动,吃小食物成长。游戏状态记录每个玩家位置、大小、颜色等数据,实时同步给所有客户端。
后端用Node.js开发,使用MongoDB数据库。前端用React结合Canvas实现客户端交互和渲染效果。
专业软件开发需要负更多责任,必须在团队中工作,通常为获得报酬开发,工作期限不定取决于企业需求。自由开发则没有这些限制,可自由决定工作内容和时间。
LinkedIn上与同学、朋友保持联系,他人日后可能提供工作机会。若求职困难可通过LinkedIn寻求帮助。
在线评测:测验算法和编程能力
视频面试:与面试官会谈技术问题
行为面试:讨论工作经历与公司文化匹配度
面试重在判断问题解决能力,不要过于在意是否知道具体解决方案。应实时思考,与面试官交流。
理顺情绪,不要过于比较其他offer或他人收入
仔细阅读offer内容,包括薪资、股票期权、奖金等
入职也要长期学习提升,不断优化自己的价值
新秀offer薪资为7-15万美元/年
股票期权和股权激励0-8万美元
签约或业绩奖金0-1.5万美元
保险和其他福利
每个新功能或个人工作都应该创建一个分支。决不应直接在主分支上工作,除非改变很小,例如修复一个问题。
如果项目中有两个人或更多,就不应该在同一个分支上工作,否则容易产生合并冲突。
理想情况下,工作应该始终在新的分支上进行,即使只有一个人进行开发。
拉取请求(Pull Request)允许将一个分支的更改合并到另一个分支中。
它允许比较两个分支之间的差异,然后将一个分支(例如功能分支)上的提交合并到另一个分支(例如主分支)上。
当两个分支产生冲突时,文件在同一行代码中的内容不同,这就产生了版本冲突。
版本冲突通过解决合并冲突来解决,即选择分支中哪些代码应该保留,哪些应该舍弃。
合并冲突通常发生在:
如果两个人在同一个分支上工作,其中一个人提交代码,另一个人没有同步更新而继续工作时。
当将功能分支合并到主分支时。
GitHub的用户界面可以查看和解决合并冲突。它允许看到不同分支中相同文件的代码,以及需要选择的代码部分。
解决冲突后,提交合并请求将代码合并到目标分支中。
测试包括单元测试、集成测试和用户验收测试等不同类型。测试可以帮助找到和修复bug,提高代码质量。
WebRTC是浏览器中的实时通信技术,能实现 audio,video以及数据的实时传输。
它的主要用途是实时通信应用,比如视频通话软件(如Zoom)。
不同于传统通过服务器中转数据的模型,WebRTC采用点对点的方式,客户端之间可以直接传输数据,减少服务器负载。
WebRTC通信需要两个主要组成部分:STUN服务器和信令服务器。
STUN服务器用于告诉客户端它的公网IP地址和网络配置,解决客户端无法直接连接的问题。
原因是网络地址转换(NAT)导致内外网IP不一致,STUN服务器通过端口映射等技术获取公网IP,让客户端能直接连接。
信令服务器是嵌入在应用程序中的,它用于客户端建立初步连接,交换会话信息。
一旦连接建立,客户端间就可以直接通信,无需通过服务器中转。
有些网络环境下,由于防火墙或代理等因素,STUN无法工作。
这时候需要使用转发服务器(TURN服务器)来替代STUN服务器,TURN服务器会将数据包传输给对方客户端。
但TURN服务需要服务器支持,效率不如直接点对点传输。WebRTC设计的是尽可能直接通信,只有STUN失败时才使用TURN servers。
提供了一个简单的WebRTC Demo示例网站:
从案例可以看到WebRTC能很好实现低延迟和高性能的实时通信需求。
本节讲解了如何部署应用到生产环境。
首先,需要在GitHub Student获取学生身份验证。这需要5分钟完成。
然后,注册Heroku账户并添加支付信息。Heroku现在只免费提供1年服务。
在Heroku创建新应用,连接到GitHub仓库。选择部署的分支,开始手动部署。
部署期间,Heroku会动态分配应用的端口。因此不能在代码中直接指定固定端口3000,而应使用process.env.PORT获取端口号。
初次部署时会出现错误,因为Catbook代码中使用了固定端口3000。
可以通过查看Heroku日志,发现部署失败是因为未在60秒内绑定端口。
解决办法是在服务器代码中,将listen从3000改为process.env.PORT,即通过环境变量获取端口号。
Heroku会添加端口号到环境变量process.env中供应用读取。本地开发时也可以设置环境变量PORT指定端口,与Heroku一致。
总结地,部署应用主要步骤是:
当进行 web 项目或任何项目时,最重要的一点就是规划。在开始编码和设计之前,首先需要规划你的 web 应用。
规划可以帮助你 stay 有组织,节省很多时间。虽然直接进入代码最激动人心,但通过规划可以获得很长的效果。
全栈开发指的是在设计一个功能时,同时考虑前端、后端和数据库层面的内容。
如设计个人主页功能:
将每个功能单独设计,包含所有需要的细节。
绘制原型纸:在 Figma 等软件上画 Wireframe
构建前端组件框架:定义状态、props 等
设计 API:定义需要的 API 端点
设计数据库模型:根据需要存储什么数据设计 Schema
编码实现:将设计翻译成代码
将每个细节一步步规划开来,就可以实现一个完整的功能模块。
随着项目不断更新,设计也会有变化。需要时刻跟踪和更新原始规划,以免产生不匹配或 bug。
规划还可以作为团队内部的交流和沟通依据。
使用工具如 Slack 进行无障碍的团队协作与沟通。及时交流设计决定,保持协调一致。
主持人介绍了这次大会的组织部门和支持单位,感谢他们为大会提供后勤支持。
支持单位包括:
也感谢课程组老师们为学生提供帮助。
这次课程历时25天,有450多学生报名参加,其中有些报有学分,有些参加竞赛,有些只是为了学习。
学生提交了88个Web应用,在Piazza上发布了489条帖子,7分钟平均回复时间。举办了许多现场授课和rackingathon等活动。
课程内容包含:
希望可以让学生对这些热门技术有一个整体了解。
选择了11个优秀项目作为半决赛项目,每个项目有5分钟时间展示自己的项目。
第一个项目是“CSS飞船”,使用CSS改变宇宙结构,收集金币、运送乘客等,带给别人有趣的游戏体验。
感谢本次活动的各个支持单位和赞助商。将在后续活动中公布11个半决赛项目的奖项。