0%

当自己都觉得代码看起来不爽,或者不好读懂时 ,这块代码一定写的有问题。

在《Clean Code》一书中Bob大叔认为在代码阅读过程中人们说脏话的频率是衡量代码质量的唯一标准。

最近再看浏览器方面的内容,对于渲染这块收集到的知识做个小结,我是大自然的搬运工。

By Ilya Grigorik

CSSOM 树和 DOM 树合并成渲染树,然后用于计算每个可见元素的布局,并输出给绘制流程,将像素渲染到屏幕上。优化上述每一个步骤对实现最佳渲染性能至关重要。

在前面介绍构建对象模型的章节中,我们根据 HTML 和 CSS 输入构建了 DOM 树和 CSSOM 树。 不过,它们都是独立的对象,分别网罗文档不同方面的信息:一个描述内容,另一个则是描述需要对文档应用的样式规则。我们该如何将两者合并,让浏览器在屏幕上渲染像素呢?

TL;DR

  • DOM 树与 CSSOM 树合并后形成渲染树。
  • 渲染树只包含渲染网页所需的节点。
  • 布局计算每个对象的精确位置和大小。
  • 最后一步是绘制,使用最终渲染树将像素渲染到屏幕上。

第一步是让浏览器将 DOM 和 CSSOM 合并成一个“渲染树”,网罗网页上所有可见的 DOM 内容,以及每个节点的所有 CSSOM 样式信息。

将 DOM 与 CSSOM 合并以形成渲染树

为构建渲染树,浏览器大体上完成了下列工作:

  1. 从 DOM 树的根节点开始遍历每个可见节点。
    • 某些节点不可见(例如脚本标记、元标记等),因为它们不会体现在渲染输出中,所以会被忽略。
    • 某些节点通过 CSS 隐藏,因此在渲染树中也会被忽略,例如,上例中的 span 节点—不会出现在渲染树中,—因为有一个显式规则在该节点上设置了“display: none”属性。
  2. 对于每个可见节点,为其找到适配的 CSSOM 规则并应用它们。
  3. 发射可见节点,连同其内容和计算的样式。

Note: 简单提一句,请注意 visibility: hiddendisplay: none 是不一样的。前者隐藏元素,但元素仍占据着布局空间(即将其渲染成一个空框),而后者 (display: none) 将元素从渲染树中完全移除,元素既不可见,也不是布局的组成部分。

最终输出的渲染同时包含了屏幕上的所有可见内容及其样式信息。有了渲染树,我们就可以进入“布局”阶段。

到目前为止,我们计算了哪些节点应该是可见的以及它们的计算样式,但我们尚未计算它们在设备视口内的确切位置和大小—这就是“布局”阶段,也称为“自动重排”。

为弄清每个对象在网页上的确切大小和位置,浏览器从渲染树的根节点开始进行遍历。让我们考虑下面这样一个简单的实例:

1
2
3
4
5
6
7
8
9
10
11
12
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Critial Path: Hello world!</title>
</head>
<body>
<div style="width: 50%">
<div style="width: 50%">Hello world!</div>
</div>
</body>
</html>

试一下

以上网页的正文包含两个嵌套 div:第一个(父)div 将节点的显示尺寸设置为视口宽度的 50%,—父 div 包含的第二个 div—将其宽度设置为其父项的 50%;即视口宽度的 25%。

计算布局信息

布局流程的输出是一个“盒模型”,它会精确地捕获每个元素在视口内的确切位置和尺寸:所有相对测量值都转换为屏幕上的绝对像素。

最后,既然我们知道了哪些节点可见、它们的计算样式以及几何信息,我们终于可以将这些信息传递给最后一个阶段:将渲染树中的每个节点转换成屏幕上的实际像素。这一步通常称为“绘制”或“栅格化”。

上述步骤都需要浏览器完成大量工作,所以相当耗时。不过,Chrome DevTools 可以帮助我们对上述所有三个阶段进行深入的了解。让我们看一下最初“hello world”示例的布局阶段:

在 DevTools 中评估布局

  • “Layout”事件在时间线中捕获渲染树构建以及位置和尺寸计算。
  • 布局完成后,浏览器会立即发出“Paint Setup”和“Paint”事件,将渲染树转换成屏幕上的像素。

执行渲染树构建、布局和绘制所需的时间将取决于文档大小、应用的样式,以及运行文档的设备:文档越大,浏览器需要完成的工作就越多;样式越复杂,绘制需要的时间就越长(例如,单色的绘制开销“较小”,而阴影的计算和渲染开销则要“大得多”)。

最后将在视口中看到下面的网页:

完成渲染的 Hello World 网页

下面简要概述了浏览器完成的步骤:

  1. 处理 HTML 标记并构建 DOM 树。
  2. 处理 CSS 标记并构建 CSSOM 树。
  3. 将 DOM 与 CSSOM 合并成一个渲染树。
  4. 根据渲染树来布局,以计算每个节点的几何信息。
  5. 将各个节点绘制到屏幕上。

我们的演示网页看起来可能很简单,实际上却需要完成相当多的工作。如果 DOM 或 CSSOM 被修改,您只能再执行一遍以上所有步骤,以确定哪些像素需要在屏幕上进行重新渲染。

*优化关键渲染路径*就是指最大限度缩短执行上述第 1 步至第 5 步耗费的总时间。 这样一来,就能尽快将内容渲染到屏幕上,此外还能缩短首次渲染后屏幕刷新的时间,即为交互式内容实现更高的刷新率。

来源:

圆桌派第四季中有一期《情绪:你心情好吗?心能管理吗?》中,窦文涛先生讲了一句话始于愤怒必终于羞愧。

真的建议大家挤出一些时间看看圆桌派,四剑客在一起时是最好看的,聊的东西真的挺有收获。

这一期我印象最深的就是这句话:始于愤怒必终于羞愧

因为我一回想当自己愤怒时候的样子和做的事说的话,大多数情况下等平静之后都会有一股愧疚感,会感到很羞愧。而你要知道这样的伤害特别是对他人可能是永久的,很多时候你根本找补不回来。

所以当你愤怒的时候,或者你觉得你情绪有问题的时候用下面的语录来一遍,可能这事就过去了。

语录:

  1. 有时候事情的沉重程度只是源于自己当时的情绪,当情绪改变了,对同一件事情的看法也就发生了改变。
  2. 出身不太好的人往往在人际交往中有很强的自我觉察,对自己的观点不够自信。
  3. 有些不良情绪在同相应的对象进行了表达之后会降低(对别人的嫉妒,说出来之后就会变好)。
  4. 王阳明心学:吾性自足。需要心胸足够开阔,装下自己,也要装下别人。
  5. 不快乐的原因是太过关注自己的情绪,所以快乐的方式是注意力向外,多关注生活,同时这也是将整个世界放到自己的心胸里,让自己变得开阔。
  6. 如果在情绪激动的时候,可以分离出一个自觉,能够看到自己正在愤怒中,就不会失控。
  7. 温度计测量温度的高低,但其本身没有温度的变化,所以才能测量温度。人的情绪也需要这样一个不会变化的量尺。
  8. 环境影响人对事情的接受程度
  9. 内在与外在的二元对立关系需要达到平衡。

小结

共勉吧,愤怒通常是瞬间发生的,先强制断一下节奏,不让愤怒和接下来的言行无缝衔接,不管用什么方式有意的断一下节奏之后,就算依然愤怒依然付诸言行也会合理很多。

我就是这样做的,大多数情况下…

浏览器是否支持

https://github.com/wesbos/beginner-javascript/

https://javascript.info/

https://wesbos.com/javascript/01-the-basics/welcome

https://www.freecodecamp.org/learn

https://medium.com/@gordon_zhu/how-to-be-great-at-asking-questions-e37be04d0603

https://www.theodinproject.com/paths/foundations/courses/foundations/lessons/html-and-css-basics

https://www.theodinproject.com/paths/foundations/courses/foundations/lessons/html-and-css-basics

https://github.com/zero-to-mastery/resources/blob/master/JavaScript.md

https://www.freecodecamp.org/news/a-beginners-javascript-study-plan-27f1d698ea5e/

https://github.com/WebHu/art-of-node

https://eloquentjavascript.net/

https://every-layout.dev/layouts/stack/

https://developer.mozilla.org/zh-CN/docs/Web/CSS/Specificityper.mozilla.org/zh-CN/docs/Web/CSS/Specificityocs/Web/CSS/Specificity

about: https://www.freecodecamp.org/learn/javascript-algorithms-and-data-structures/basic-javascript/iterate-with-javascript-while-loops There’s a few lessons on different kinds of loops, is just the first.There’s also a section in The Odin Project on loops that you can check out: https://www.theodinproject.com/paths/foundations/courses/foundations/lessons/fundamentals-part-4And here’s a book on Javascript, but I’ll just include the link to the loop section: https://cdn.gomakethings.com/products/vanilla-js-pocket-guide-sample.pdf#__WKANCHOR_m Aaaaand, finally, since you’re new to Javascript, here’s a giant list of places to learn all the things: https://github.com/zero-to-mastery/resources/blob/master/JavaScript.md (There a bunch of info there and not all of it is immediately necessary for you, so don’t let the length overwhelm ya!)

Best of luck! JavaScript.md**</README.md/|Back>****Resources to Become a JavaScript Expert

W3Schools JavaScript Tutorial Examples, and documentations, for those who are advanced, and beginners, to learn JavaScript.

A JavaScript Curriculum: A great curriculum for learning JavaScript from newbie to You Don’t Know JS.

The Art of Node: Short introduction to Node that has some great information.

Eloquent JavaScript: Eloquent JavaScript goes beyond the cut-and-paste scripts of the recipe books and teaches you to write code that’s elegant and effective. You’ll start with the basics of programming, and learn to use variables, control structures, functions, and data structures. Then you’ll dive into the real JavaScript artistry: higher-order functions, closures, and object-oriented programming. Highly recommended.

Exploring JS: JavaScript books for programmers by Dr. Axel Rauschmeyer: free online books that delve deep into the Javascript language - always up-to-date with new books on the latest Ecmascript features

A brief history of JavaScript by Ben Aston: It is a medium article describing and throwing light upon the History of JavaScript.

FreeCodeCamp Beginning JavaScript: Learn JavaScript with an online community, examples, and tons of more advanced JavaScript topics when you are done. Certificate available too. All free.

Functional Light JS: Pragmatic, balanced Functional Programming in JavaScript.

JavaScript Cookbook: Why reinvent the wheel every time you run into a problem with JavaScript? This cookbook is chock-full of code recipes that address common programming tasks, as well as techniques for building web apps that work in any browser. Just copy and paste the code samples into your project—you’ll get the job done faster and learn more about JavaScript in the process.• JavaScript For Cats: An introduction for new programmers.

JavaScript Fundamentals on Codecademy: You will learn programming fundamentals and basic object-oriented concepts using the latest JavaScript syntax. The concepts covered in these lessons lay the foundation for using JavaScript in any environment.

JavaScript Fundamentals for Absolute Beginners: A 7 hour long video with detailed explanations to give a strong foundation in JavaScript fundamentals. Taught by Bob Tabor, one of the most effective web development teachers.

JavaScript Jabber: A weekly podcast discussing the superb language JavaScript.• JavaScript.Info: How it’s done now. From the basics to advanced topics with simple with JavaScript, but detailed explanations.

JavaScript: The Core: This is a very solid foundation to work with, for anyone who might have struggled with the contexts and how arrow functions, local variables, and prototypes fit into the bigger picture. A quick introduction into the deeper ideas in JavaScript.

JavaScript30: A 30-day coding challenge in which you will build 30 things using vanilla JavaScript.

JS Fiddle: JSFiddle is an online community to test and collaborate JavaScript code snippets, known as ‘fiddles’. It also allows for simulated AJAX calls. It can also be used to test HTML & CSS.

Mixu’s Node Book: An online tutorial that received much praise for explaining Node.js in a well-structured way. It is a book that teaches you to write the code for Node.js and not only rely on third-party libraries. Anyone that wants to have a deep grasp of the Node.js framework will benefit from Mixu’s book.

**• Practical JavaScript: The excellent teachers at Watch and Code have released their beginning JavaScript course for free. If you haven’t been able to learn elsewhere, try this tutorial.

State of JavaScript: An annual survey of over 20,000 JavaScript developers regarding the major JavaScript libraries, frameworks, languages, and other tools. A useful resource for understanding where the industry is headed and deciding what to learn next.

You Don’t Know JS: No matter how much experience you have with JavaScript, odds are you don’t fully understand the language. These concise yet in-depth guides take you inside core concepts that can help you become a more efficient and effective JavaScript programmer. This is a series of books diving deep into the core mechanisms of the JavaScript language.

Edabit JavaScript Challenges: Learn JavaScript with real world, interactive challenges. Gain XP, unlock achievements and level up. It’s kind of like Duolingo for learning to code.

JS Tips - A JavaScript tip per day!: JS Tips is a collection of useful daily JavaScript tips that will allow you to improve your code writing.

The Complete JavaScript Course 2020: Build Real Projects! A comprehensive video course from beginner to mastery with real world projects.• Superhero.js: This page is a collection of the best articles, videos and presentations related to JavaScript.

a smarter way to learn : javascript exercises for beginners

JavaScript for Complete Beginners - Interactive Tutorial: A short interactive website which has exercises for introducing new programmers to the primary concepts in JavaScript.

JavaScript ES6: Scrimba: Learn JavaScript ES6 concepts with this short, interactive course at Scrimba. This includes interactive screencasts so you can learn along with the teacher. This is a pretty unique way of instruction.

MDN Web Docs: This provides different tutorials for JavaScript, resources and an explanation of the JavaScript.Advanced Javascript Articles

Exploring Async/Await Functions in JavaScript: Async/await functions, a new addition with ES2017 (ES8), help us even more in allowing us to write completely synchronous-looking code while performing asynchronous tasks behind the scenes.

A simple guide to help you understand closures in JavaScript: A closure is a function that has access to its outer function scope even after the return of the outer function (For better understanding head inside the blog).Tools, Frameworks, and Libraries

JavaScript Array Explorer: Find the array method you need for your JavaScript array without digging through the docs. A useful resource that can make using arrays easier.

Javascript Object Explorer: The same tool for objects.

Linting ES2015+ — ESLint with StyleGuides: Google, AirBnB, Common: An excellent breakdown of linting’s purpose and history while also g…

css动画

https://openhome.cc/eGossip/JavaScript/Event.html

https://www.w3.org/TR/WD-DOM-Level-2/events.html

https://www.quirksmode.org/js/events_early.html

https://html.spec.whatwg.org/

https://www.w3.org/TR/DOM-Level-3-Events/#event-flow

项目前期运维工具没有铺开的时候很多时候都是直接上服务器敲命令,这里记录一下source命令,也是某段时间很常用的一个命令。

我用source命令主要是为了刷新环境变量。刚好前段时间看到一篇文章

https://linuxhandbook.com/source-command/,对source命令有了更深入的了解,在这搬运一下。

Linux中的源命令是什么?

source命令的是从当前shell中的文件执行。它也可以用于刷新环境变量,通常source命令的主要用途是刷新环境变量。

1
source filename [options]

您也可以使用.(点)代替这样的源命令:

1
. filename [options]

源命令如何工作?

该命令的语法很简单,但是要理解它,需要更深入地了解一些Linux概念。

在继续之前,我先对变量给出一个简短的解释。

变量概述

您可以打开任何bash终端并创建新变量。变量可以被视为占位符,可用于将系统指向一条信息(字母,数字或符号)。

让我们来看一个例子。我将创建一个名为name的新变量,并将为值Christopher赋值。

在bash中,这是使用公式完成的:variable_name = your_variable。请勿在**=**符号和您的文本之间添加任何空格。

1
2
3
christopher@linuxhandbook:~$ name=Christopher
christopher@linuxhandbook:~$ echo $name
Christopher

如果我只输入变量名会怎样?

1
2
christopher@linuxhandbook:~$ echo name
name

如果您忘记了该符号,bash将返回您输入的文本。在这里,我告诉它回显或打印“名称”。没有$符号,bash无法识别您要使用已创建的变量。

您的变量将被插入到调用它的位置。因此,我也可以将其包含在这样的句子中:

1
2
christopher@linuxhandbook:~$ echo "Hello, $name. $name is a great name. It's good to meet you."
Hello, Christopher. Christopher is a great name. It's good to meet you.

您可以使用变量做很多事情,但是我希望该入门足以使任何阅读本文的人都能理解它们的工作原理。

环境变量与shell(本地)变量

对于理解源命令的下一个关键,让我们谈谈持久性。这是考虑shell变量和环境变量之间差异的简便方法。您可能还根据上下文根据“可移植性”来考虑它。

简而言之,如果在终端shell中创建变量,则退出该shell后该变量将丢失。

相反,环境变量在您的操作系统中具有持久性。这些变量通常使用所有大写字母来区分自己。

例如,您的用户名被操作系统称为$ USER。

1
2
christopher@linuxhandbook:~$ echo $USER
christopher

好的,因此您花了很多时间来研究环境变量和shell变量之间的差异。这与source有什么关系?如果不了解这块则,运行sourcebash不会有任何区别。

Source vs Bash

如果您使用Linux已有一段时间,那么您可能会遇到这些命令,并认为它们做了相同的事情。毕竟,这两个命令都可以用来执行脚本。

source在当前shell中工作,与运行bash会创建一个新shell不同。这并不明显,因为没有显示新窗口。

比如编写一个非常简单的脚本(将其称为echo.sh),如下所示:

1
2
3
4
#! bin/bash

echo $USER
echo $name

在终端中执行其他任何操作之前,请将值分配给变量名称。

1
christopher@linuxhandbook:~$ name=chris

接下来,我将向您展示在分配变量的同一终端中尝试所有3条命令时会发生什么。

1
2
3
4
5
6
7
8
9
christopher@linuxhandbook:~$ bash echo.sh 
christopher

christopher@linuxhandbook:~$ source echo.sh
christopher
chris
christopher@linuxhandbook:~$ . echo.sh
christopher
chris

如您所见,通过bash执行脚本时,无法识别本地变量。

使用source命令刷新环境变量

Source也可以用于更新当前Shell中的环境变量。此任务的常见应用程序是在当前shell中更新bash配置文件。

用户可能想要修改其bash配置文件以创建别名。通常,一旦保存了配置,您将需要打开一个新的终端窗口以进行更改。

1
christopher@linuxhandbook:~$ source .bashrc 

运行此命令将刷新当前外壳程序中的设置,而不会强制您打开新终端。

通过几个迭代后,前端代码变得越来越臃肿越来越乱。所以编码规范就排上日程。

结合这段时间我们的经验加上从网上搜集到的实用的编码规范,做一个简单整理。

前端编码规范意见稿

  • 统一ESLint文件
    • 比如用Airbnb,随着积累可以在其基础上进行扩展。
  • React组件
    • 如果组件需要维护自己的state或者使用其生命周期方法则用class,除此以外都用function。
  • Redux
    • 除了纯渲染组件(没有复杂的交互、逻辑),其余都用redux
              redux使代码结构更加清晰,可读性较强便于维护(倒逼组件或者模块拆的更加合理)。
              redux可当成全局内存库来用,当没有更新state时,无论何时何地都能到一样的数据,便于通用组件的开发
              redux可以减少数据的传递,不用依次往下传,随用随取,特别是针对组件层级比较深的情况
      
  • 统一格式化插件(如果要用格式化插件)
    • 比如VSCode的prettier或者beauty,千万避免多人用多套格式化插件的情况

JS开发规范

对象

  • 不要使用关键字作为key或者属性
    1
    2
    3
    4
    5
    6
    7
    8
    9
    // bad
    var user = {
    private: true
    };

    // good
    var user = {
    hidden: true
    };

数组

  • 如果你不知道数组的长度,使用push

    1
    2
    3
    4
    5
    6
    7
    8
    var userArr = [];


    // bad
    userArr[index] = 'gamehu';

    // good
    userArr.push('gamehu');
  • 当你需要拷贝数组时

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    var len = users.length,
    usersCopy = [],
    i;

    // bad
    for (i = 0; i < len; i++) {
    usersCopy[i] = items[i];
    }

    // good
    usersCopy = users.slice();

    //good ES6

    usersCopy = [...users];

    usersCopy=Array.from(users);


  • 将类数组的对象转成数组.

    1
    2
    3
    4
    5
    let args = [].slice.apply(users);

    // ES6
    let args=Array.from(users);

字符串

  • 对字符串使用单引号 ‘’
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    // bad
    var name = "Gamehu";

    // good
    var name = 'Gamehu';

    // bad
    var fullName = "Gamehu " + this.lastName;

    // good
    var fullName = 'Gamehu ' + this.lastName;

函数

  • 绝对不要把参数命名为 arguments, 将覆盖作用域内传过来的 arguments 对象.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    // bad
    function nope(name, options, arguments) {
    // ...stuff...
    }

    // good
    function yup(name, options, args) {
    // ...stuff...
    }
  • 当函数的参数特别多的时候用对象封装起来再传递.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16

    //bad

    export const resourceStoreDynamicFormForEdit = (group, data, index, form, editableIndex, sortItems, formItemLayout, validatorMap, dataMap, ciType, selectedCiEditable, showAlarmSlowStrategy) => {}

    // good

    const params={};

    params={
    group:group, xxx
    }

    export const resourceStoreDynamicFormForEdit=(params) ={
    }

  • 函数应该只在一个抽象层次上做一件事.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30

    // bad
    function getUserRouteHandler (req, res) {
    const { userId } = req.params
    // inline SQL query
    knex('user')
    .where({ id: userId })
    .first()
    .then((user) => res.json(user))
    }

    // good
    // User model (eg. models/user.js)
    const tableName = 'user'
    const User = {
    getOne (userId) {
    return knex(tableName)
    .where({ id: userId })
    .first()
    }
    }

    // route handler (eg. server/routes/user/get.js)
    function getUserRouteHandler (req, res) {
    const { userId } = req.params
    User.getOne(userId)
    .then((user) => res.json(user))
    }


  • 更高层次的函数在低层次函数的前面,便于阅读.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    // bad
    // "I need the full name for something..."
    function getFullName (user) {
    return `${user.firstName} ${user.lastName}`
    }

    function renderEmailTemplate (user) {
    // "oh, here"
    const fullName = getFullName(user)
    return `Dear ${fullName}, ...`
    }

    // good
    function renderEmailTemplate (user) {
    // "I need the full name of the user"
    const fullName = getFullName(user)
    return `Dear ${fullName}, ...`
    }

    // "I use this for the email template rendering"
    function getFullName (user) {
    return `${user.firstName} ${user.lastName}`
    }
  • 声明函数时最好设置默认值.

    1
    2
    3
    //es6
    function (a=1, b=1) { // function code }

  • 如果想避免var变量造成的命名冲突,不存在特殊场景时可考虑使用立即执行函数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    立即执行函数,即Immediately Invoked Function Expression (IIFE),正如它的名字,
    就是创建函数的同时立即执行。它没有绑定任何事件,也无需等待任何异步操作:
    (function() {
    // 代码
    // ...
    })();
    function(){…}是一个匿名函数,包围它的一对括号将其转换为一个表达式,
    紧跟其后的一对括号调用了这个函数。立即执行函数也可以理解为立即调用一个匿名函数。
    立即执行函数最常见的应用场景就是:将var变量的作用域限制于你们函数内,这样可以避免命名冲突。


  • 当有场景需要使用私有属性时,使用闭包定义私有变量

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    function Product() {

    var name;

    this.setName = function(value) {
    name = value;
    };

    this.getName = function() {
    return name;
    };
    }

    var p = new Product();
    p.setName("Fundebug");

    console.log(p.name); // 输出undefined
    console.log(p.getName()); // 输出Fundebug
    代码中,对象p的的name属性为私有属性,使用p.name不能直接访问。


变量

  • 总是使用 let、const、var来声明变量,如果不这么做将导致产生全局变量,我们要避免污染全局命名空间。

    1
    2
    3
    4
    5
    // bad
    superPower = new SuperPower();

    // good
    var superPower = new SuperPower();
  • 使用一个 let 以及新行声明多个变量,缩进4个空格。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    // bad
    let items = getItems();
    let goSportsTeam = true;
    let dragonball = 'z';

    // good
    let items = getItems(),
    goSportsTeam = true,
    dragonball = 'z';
  • 最后再声明未赋值的变量,当你想引用之前已赋值变量的时候很有用。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    // bad
    var i, len,hidden = true,
    items = getItems();

    // bad
    var i, items = getItems(),
    hidden = true,
    len;

    // good
    var items = getItems(),
    hidden = true,
    length,
    i;
  • 在作用域顶部声明变量,避免变量声明和赋值引起的相关问题。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    // bad
    function() {
    test();
    console.log('doing stuff..');

    //..other stuff..

    var name = getName();

    if (name === 'test') {
    return false;
    }

    return name;
    }

    // good
    function() {
    var name = getName();

    test();
    console.log('doing stuff..');

    //..other stuff..

    if (name === 'test') {
    return false;
    }

    return name;
    }

    // bad
    function() {
    var name = getName();

    if (!arguments.length) {
    return false;
    }

    return true;
    }

    // good
    function() {
    if (!arguments.length) {
    return false;
    }

    var name = getName();

    return true;
    }
  • 在声明变量时初始化变量。

    1
    2
    3
    4
    5
    6
    7
    8
    var firstName = "",
    lastName = "",
    price = 0,
    discount = 0,
    fullPrice = 0,
    myArray = [],
    myObject = {};

  • 在声明变量时别用对象。

    1
    2
    3
    4
    5
    6
    7
    8
    Use {} instead of new Object()
    Use "" instead of new String()
    Use 0 instead of new Number()
    Use false instead of new Boolean()
    Use [] instead of new Array()
    Use /()/ instead of new RegExp()
    Use function (){} instead of new Function()

  • 用===代替==,因为==会在比较之前进行类型转换。

    1
    2
    3
    4
    5
    6
    7
    8
    0 == "";        // true
    1 == "1"; // true
    1 == true; // true

    0 === ""; // false
    1 === "1"; // false
    1 === true; // false

  • 注意数字和字符串之间的转换。

    1
    2
    3
    4
    5
    6
    7
    8
    var x = 5 + 7;       // x.valueOf() is 12,  typeof x is a number
    var x = 5 + "7"; // x.valueOf() is 57, typeof x is a string
    var x = "5" + 7; // x.valueOf() is 57, typeof x is a string
    var x = 5 - 7; // x.valueOf() is -2, typeof x is a number
    var x = 5 - "7"; // x.valueOf() is -2, typeof x is a number
    var x = "5" - 7; // x.valueOf() is -2, typeof x is a number
    var x = 5 - "x"; // x.valueOf() is NaN, typeof x is a number

  • 在for循环的每次迭代中都不要让JavaScript读取数组的长度。 将长度值存储在另一个变量中。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    //bad
    var names = ['George',
    'Ringo',
    'Paul',
    'John'];
    for(var i=0;i<names.length;i++){
    doSomethingWith(names[i]);
    }

    //good
    var names = ['George',
    'Ringo',
    'Paul',
    'John'];
    for(var i=0,j=names.length;i<j;i++){
    doSomethingWith(names[i]);
    }

条件表达式和等号

  • 合理使用 === 和 !== 以及 == 和 !=.

  • 合理使用表达式逻辑操作运算

  • 条件表达式的强制类型转换遵循以下规则:

  • switch时一定要用default结束

    1
    2
    3
    4
    5
    6
    7
    1: 对象 被计算为 true
    2: Undefined 被计算为 false
    3: Null 被计算为 false
    4: 布尔值 被计算为 布尔的值
    5: 数字 如果是 +0, -0, or NaN 被计算为 false , 否则为 true
    6: 字符串 如果是空字符串 '' 则被计算为 false, 否则为 true

  • 使用快捷方式

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    // bad
    if (name !== '') {
    // ...stuff...
    }

    // good
    if (name) {
    // ...stuff...
    }

    // bad
    if (collection.length > 0) {
    // ...stuff...
    }

    // good
    if (collection.length) {
    // ...stuff...
    }

    //bad
    if(v){
    var x = v;
    } else {
    var x =10;
    }

    //good
    var x = v || 10;


    //bad
    var direction;
    if(x > 100){
    direction = 1;
    } else {
    direction = -1;
    }

    //good
    var direction = (x > 100) ? 1 : -1;


  • 给所有多行的块使用大括号
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    // bad
    if (test)
    return false;

    // good
    if (test) return false;

    // good
    if (test) {
    return false;
    }

    // bad
    function() { return false; }

    // good
    function() {
    return false;
    }

注释

  • 使用 /** … */ 进行多行注释,包括描述,指定类型以及参数值和返回值

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
     // bad
    // make() returns a new element
    // based on the passed in tag name
    //
    // @param <String> tag
    // @return <Element> element
    function make(tag) {

    // ...stuff...

    return element;
    }

    // good
    /**
    * make() returns a new element
    * based on the passed in tag name
    *
    * @param <String> tag
    * @return <Element> element
    */
    function make(tag) {

    // ...stuff...

    return element;
    }
  • 使用 // 进行单行注释,在评论对象的上面进行单行注释,注释前放一个空行.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
     // bad
    var active = true; // is current tab

    // good
    // is current tab
    var active = true;

    // bad
    function getType() {
    console.log('fetching type...');
    // set the default type to 'no type'
    var type = this._type || 'no type';

    return type;
    }

    // good
    function getType() {
    console.log('fetching type...');

    // set the default type to 'no type'
    var type = this._type || 'no type';

    return type;
    }
  • 如果你有一个问题需要重新来看一下或如果你建议一个需要被实现的解决方法的话需要在你的注释前面加上 FIXME 或 TODO 帮助其他人迅速理解

    1
    2
    3
    4
    5
    6
    7
     function Calculator() {

    // FIXME: shouldn't use a global here
    total = 0;

    return this;
    }
    1
    2
    3
    4
    5
    6
    7
     function Calculator() {

    // TODO: total should be configurable by an options param
    this.total = 0;

    return this;
    }

空白

  • 缩进、格式化能帮助团队更快得定位修复代码BUG.

  • 将tab设为4个空格

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    // bad
    function() {
    ∙∙var name;
    }

    // bad
    function() {
    ∙var name;
    }

    // good
    function() {
    ∙∙∙∙var name;
    }
  • 大括号前放一个空格

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    {
    // bad
    function test(){
    console.log('test');
    }

    // good
    function test() {
    console.log('test');
    }

    // bad
    dog.set('attr',{
    age: '1 year',
    breed: 'Bernese Mountain Dog'
    });

    // good
    dog.set('attr', {
    age: '1 year',
    breed: 'Bernese Mountain Dog'
    });
    }
  • 在做长方法链时使用缩进.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    // bad
    $('#items').find('.selected').highlight().end().find('.open').updateCount();

    // good
    $('#items')
    .find('.selected')
    .highlight()
    .end()
    .find('.open')
    .updateCount();

    // bad
    var leds = stage.selectAll('.led').data(data).enter().append('svg:svg').class('led', true)
    .attr('width', (radius + margin) * 2).append('svg:g')
    .attr('transform', 'translate(' + (radius + margin) + ',' + (radius + margin) + ')')
    .call(tron.led);

    // good
    var leds = stage.selectAll('.led')
    .data(data)
    .enter().append('svg:svg')
    .class('led', true)
    .attr('width', (radius + margin) * 2)
    .append('svg:g')
    .attr('transform', 'translate(' + (radius + margin) + ',' + (radius + margin) + ')')
    .call(tron.led);

逗号

  • 不要将逗号放前面

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    // bad
    var once
    , upon
    , aTime;

    // good
    var once,
    upon,
    aTime;

    // bad
    var hero = {
    firstName: 'Bob'
    , lastName: 'Parr'
    , heroName: 'Mr. Incredible'
    , superPower: 'strength'
    };

    // good
    var hero = {
    firstName: 'Bob',
    lastName: 'Parr',
    heroName: 'Mr. Incredible',
    superPower: 'strength'
    };
  • 不要加多余的逗号,这可能会在IE下引起错误,同时如果多一个逗号某些ES3的实现会计算多数组的长度。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    // bad
    var hero = {
    firstName: 'Kevin',
    lastName: 'Flynn',
    };

    var heroes = [
    'Batman',
    'Superman',
    ];

    // good
    var hero = {
    firstName: 'Kevin',
    lastName: 'Flynn'
    };

    var heroes = [
    'Batman',
    'Superman'
    ];

分号

  • 语句结束一定要加分号
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    // bad
    (function() {
    var name = 'Skywalker'
    return name
    })()

    // good
    (function() {
    var name = 'Skywalker';
    return name;
    })();

    // good
    ;(function() {
    var name = 'Skywalker';
    return name;
    })();

类型转换

  • 在语句的开始执行类型转换.

  • 字符串

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    //  => this.reviewScore = 9;

    // bad
    var totalScore = this.reviewScore + '';

    // good
    var totalScore = '' + this.reviewScore;

    // bad
    var totalScore = '' + this.reviewScore + ' total score';

    // good
    var totalScore = this.reviewScore + ' total score';
  • 对数字使用 parseInt 并且总是带上类型转换的基数.,如parseInt(value, 10)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    var inputValue = '4';

    // bad
    var val = new Number(inputValue);

    // bad
    var val = +inputValue;

    // bad
    var val = inputValue >> 0;

    // bad
    var val = parseInt(inputValue);

    // good
    var val = Number(inputValue);

    // good
    var val = parseInt(inputValue, 10);

    // good
    /**
    * parseInt was the reason my code was slow.
    * Bitshifting the String to coerce it to a
    * Number made it a lot faster.
    */
    var val = inputValue >> 0;
  • 布尔值

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    var age = 0;

    // bad
    var hasAge = new Boolean(age);

    // good
    var hasAge = Boolean(age);

    // good
    var hasAge = !!age;

命名约定

  • 避免单个字符名,让你的变量名有描述意义。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    // bad
    function q() {
    // ...stuff...
    }

    // good
    function query() {
    // ..stuff..
    }
  • 当命名对象、函数和实例时使用驼峰命名规则

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    // bad
    var OBJEcttsssss = {};
    var this_is_my_object = {};
    var this-is-my-object = {};
    function c() {};
    var u = new user({
    name: 'Bob Parr'
    });

    // good
    var thisIsMyObject = {};
    function thisIsMyFunction() {};
    var user = new User({
    name: 'Bob Parr'
    });
  • 当命名构造函数或类时使用驼峰式大写

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    // bad
    function user(options) {
    this.name = options.name;
    }

    var bad = new user({
    name: 'nope'
    });

    // good
    function User(options) {
    this.name = options.name;
    }

    var good = new User({
    name: 'yup'
    });
  • 命名私有属性时前面加个下划线 _

    1
    2
    3
    4
    5
    6
    // bad
    this.__firstName__ = 'Panda';
    this.firstName_ = 'Panda';

    // good
    this._firstName = 'Panda';
  • 模块开发的常量定义必须包含“完整的模块名称“

    1
    2
    3
    4
    5
    6
    // bad
    export const GET_ASSET_LIST = 'GET_ASSET_LIST';

    // good
    export const GET_ASSET_LIST = 'ALARM_GET_ASSET_LIST';

  • 望名知意,建议驼峰命名(函数也适用)。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12

    // bad
    let fItem;

    // good
    let formItem;

    //bad
    let yUnit = unitObj.unit;

    //good
    let yAxisUnit = unitObj.unit;

存取器

  • 属性的存取器函数不是必需的
  • 如果你确实有存取器函数的话使用getVal() 和 setVal(‘hello’),java getter、setter风格或者jQuery风格
  • 如果属性是布尔值,使用isVal() 或 hasVal()
    1
    2
    3
    4
    5
    6
    7
    8
    9
    // bad
    if (!dragon.age()) {
    return false;
    }

    // good
    if (!dragon.hasAge()) {
    return false;
    }
  • 可以创建get()和set()函数,但是要保持一致
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    function Jedi(options) {
    options || (options = {});
    var lightsaber = options.lightsaber || 'blue';
    this.set('lightsaber', lightsaber);
    }

    Jedi.prototype.set = function(key, val) {
    this[key] = val;
    };

    Jedi.prototype.get = function(key) {
    return this[key];
    };

构造器

  • 给对象原型分配方法,而不是用一个新的对象覆盖原型,覆盖原型会使继承出现问题。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    function Jedi() {
    console.log('new jedi');
    }

    // bad
    Jedi.prototype = {
    fight: function fight() {
    console.log('fighting');
    },

    block: function block() {
    console.log('blocking');
    }
    };

    // good
    Jedi.prototype.fight = function fight() {
    console.log('fighting');
    };

    Jedi.prototype.block = function block() {
    console.log('blocking');
    };
  • 方法可以返回 this 帮助方法可链。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    // bad
    Jedi.prototype.jump = function() {
    this.jumping = true;
    return true;
    };

    Jedi.prototype.setHeight = function(height) {
    this.height = height;
    };

    var luke = new Jedi();
    luke.jump(); // => true
    luke.setHeight(20) // => undefined

    // good
    Jedi.prototype.jump = function() {
    this.jumping = true;
    return this;
    };

    Jedi.prototype.setHeight = function(height) {
    this.height = height;
    return this;
    };

    var luke = new Jedi();

    luke.jump()
    .setHeight(20);
  • 可以写一个自定义的toString()方法,但是确保它工作正常并且不会有副作用。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    function Jedi(options) {
    options || (options = {});
    this.name = options.name || 'no name';
    }

    Jedi.prototype.getName = function getName() {
    return this.name;
    };

    Jedi.prototype.toString = function toString() {
    return 'Jedi - ' + this.getName();
    };

事件

  • 当给事件附加数据时,传入一个哈希而不是原始值,这可以让后面维护时加入更多数据到事件数据里而不用找出并更新那个事件的事件处理器
    1
    2
    3
    4
    5
    6
    7
    8
    // bad
    $(this).trigger('listingUpdated', listing.id);

    ...

    $(this).on('listingUpdated', function(e, listingId) {
    // do something with listingId
    });
  • 更好:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    // good
    $(this).trigger('listingUpdated', { listingId : listing.id });

    ...

    $(this).on('listingUpdated', function(e, data) {
    // do something with data.listingId
    });

模块

  • 文件应该以驼峰命名,并在同名文件夹下,同时导出的时候名字一致

参考

一个小迭代结束之后,我们前端做了一个几次code revew,其中有个问题就是什么时候应该redux,因为redux其实有些重,但是某些场景其实很简单当让组件也很简单,有观点觉得没有必要上redux。

这个问题需要有个解法。

我觉得需要根据现有的环境来几个方面来考虑。

  1. 现在我们产品前端组件类别:基础组件、业务通用组件、定制化组件。
  2. 产品的体量,我们产品是ToB产品,功能比较多,代码量比较大。
  3. 业务场景的复杂度,因为是ToB,所以场景覆盖比较全,同时定制化需求稍微比较多,所以复杂度比较高。

好,接着我们再看看Redux,要讨论是否需要用它或者什么时候用它我们得搞清楚它的作用是什么。

首先咱们得确定一点React本身其实就是一个UI(View)层它不是一个前端框架, 如果是个复杂的产品,前端光负责View很显然是不够的,所以这几年出现了很多前端架构,比如MVVM架构下的Angular就是一套前端框架.

正因为这样,所以FaceBook提出了Flux的架构,就是为了能推出以React为基础的一套前端框架,让React不再孤单.

至于什么是Flux,阮老师说的很清楚: http://www.ruanyifeng.com/blog/2016/01/flux.html

看完之后你会发现,redux其实就是Flux的一种实现,主要解决两个问题:

  1. 清晰的代码层次结构,让复杂的前端变得更加健壮和易维护(action、dispatch、reducer等).
  2. 让React组件之间通信变得更有效率和更方便(通过store能在任何组件访问想要的数据,不管是横向的还是纵向的层级,而不用依次传递经过根本不需要该数据的组件,真正做到按需使用)

所以说到这儿我们可以简单列一下使用Redux的好处

  • 大多数情况下可以用reducer友好的把state从组件里分离出来,使组件更加的轻量化也增加了代码可读性.
  • Redux的store可以当成缓存使用,并且是全局的,你可以在任何地方使用它,只要不更新state,无论何时何地获取的数据都是一样的,使数据共享变得容易.
  • Redux友好的把state统一放到了store里,通过action、dispatch、reducer,让state的变化变得可预测,让数据流变得清晰明朗,易于维护.
  • Redux的store让数据的传递变得更有效率,无需依次进行数据传递(哪怕该组件根本不需要这个数据),可以满足需要的时候再获取.
  • Redux更有利于公共组件的开发,公共组件无论在哪儿使用,可以通过dispatch触发其行为.

试着回答一下

我觉得除非已经明确的定义某个组件只是一个纯UI类组件,不会存在其它业务逻辑或者行为,那我觉得没有必要用Redux,比如我们产品中的一些展示组件,这些组件一个最大的特点就是,只需要给它数据,它渲染就完事了不会有额外的一些操作,那完全就一个jsx就搞定了.除此以外都建议用Redux,虽然它复杂了些,但是你会慢慢发现他的好.

简单记录一下我平时使用搜索套路。

浏览medium的时候发现了一位大佬,继而发现了她的博客,继而读到了一篇关于“动力”的文章。觉得说的很到位,很契合我现在正努力改变而采用的方式,那就是先动起来。

这儿做个搬运工也做个自我的审视。

每天,无数人都在为动力而苦苦挣扎,或者说,缺乏动力。他们渴望做得更多,做得更好,但他们根本没有这样做的动力。

结果,他们最终过着平庸的生活,因为他们知道自己有“潜力”,但他们从未选择追求这种潜力。他们安顿在相同的套路中,发现自己希望得到比他们所收到的更多的东西。

必须有一个更好的解决方案,对不对?

我对动机问题的回答

我知道我知道。您现在可能会问我:“ 您如何保持动力?” 。我的答案很简单:

我不会试图简单地“保持积极性”。我采取行动,动机随之而来。

人们似乎认为这是相反的,我们必须等待动力来使我们采取行动。但这离事实还远!

动机不是一种神奇的能量,它只是神奇地独自出现。这是必须通过行动创造的力量。因此,真正有动力的唯一方法就是行动。如果您所做的只是将时间浪费在如意算盘上,那么您寻找的动力就永远不会到来。

每个人(即使是最成功的人)在完成任务时也有同样的恐惧感。其实我们也知道有要做的事情,但是却因为自己不想做而挣扎。

不要想太多

在很多时候不想动的时,你得遵从你的内心而不是你的大脑,你的大脑总是会让你不动,因为它就是你的潜意识,但是从内心你知道你是应该要动起来的。所以这个时候遵从自己的内心赶紧挪动屁股动起来。

要点:采取行动的人有动力

动机是当我们渴望采取行动,而我们实际上遵循这一愿望时发生的事情。如果您想获得动力,则必须采取行动。我意识到这是一个自我实现的预言,但这正是我要提出的重点。

当您采取行动时,就会积蓄动力。动量推动着你前进,你想采取更多的行动。该行动将产生更多动力,依此类推。这是一个良性循环:正反馈回路。

img

如果发现自己缺乏动力,请看一下自己的行为。如果您不采取行动,是时候开始努力了。不久之后,您会发现自己比想知道的要有更多的动力!

另一方面,零作用意味着零动量。如果您拒绝采取行动,那么您正在创建一个充满负面事物的空间。通常,这个空间充满思想:关于您应该如何或为什么或何时采取行动的想法。您的大脑过度分析了您想要完成的工作。您会发现自己正在思考完成动作所需的所有方式以及可能会失败的所有方式。

恐惧和焦虑开始发作。在这一点上,您实际上已经产生了消极的动力,并且您一开始就害怕要完成的一切。您开始下滑。

您坐下来等待动力的时间越长,就会发现的越少。

当然,并非每种情况都要求您立即投入工作而不考虑应该采取的行动。例如,假设您需要与一个浪漫的伴侣进行艰难的谈话,以结束您的恋爱关系。您害怕伤害他们,害怕伤害自己。这种恐惧削弱了您的动力,使您无意继续进行对话,即使这是100%必要的。

你该怎么办?您是否应该让这种对话像暴风雨云一样继续笼罩着您,直到您对它感到厌倦为止,只是在没有真正思考的情况下跳入对话?

没有!

在这种情况下,思考如何最好地进行对话实际上是有帮助的。有远见的人会使您免于伤害任何人的感情。考虑如何完成一项动作与考虑实际完成所述动作之间存在巨大差异。您可能需要花费数周,数月甚至数年的时间思考实际做某事,却一无所获。您必须意识到自己的想法:如果您发现自己偏离批判性思维而进入可怕的领域,那么该是停止停顿并采取行动的时候了!

让我们回到眼前的场景。设置日期和您计划与伴侣进行对话的时间。设定时间和地点会让您负责。不要让自己对这一承诺退缩-放弃只是意味着欺骗自己。

在您履行了这一承诺之后,然后-仅那时!-您是否应该开始考虑动作本身。

通过提前计划并做出承诺,您实质上改变了您的思考过程。您现在不再“呃,我不想进行对话”,而是以“好吧,我在对话中实际上会说些什么?”的心态。。这是非生产性思维与生产性思维的问题。

看到不同?😊

结论

动机的“秘密”就是行动。如果您发现自己动力不足,则可能是因为无所作为。如果您想找到动力,就需要全身心投入并开始行动!

大小无关紧要。实际上,我建议您将其缩小。我们经常想尽可能地“完成很多工作”,但这是一个不好的方法,因为它耗尽了我们的意志力。取而代之的是,您应该采取足够的措施来增强动力,但要在压力开始感到沉重之前就停止。这样,您便有意愿回来以后再做更多的事情。

现在是您采取行动的时候了。