识得唔识得啊

识得唔识得啊 查看完整档案

填写现居城市  |  填写毕业院校  |  填写所在公司/组织填写个人主网站
编辑
_ | |__ _ _ __ _ | '_ \| | | |/ _` | | |_) | |_| | (_| | |_.__/ \__,_|\__, | |___/ 个人简介什么都没有

个人动态

识得唔识得啊 收藏了文章 · 2019-10-16

网页图片缩放的深入剖析

一、浏览器图片缩放默认表现行为行为

在想出解决方案之前,首先要弄清楚浏览器对于图片尺寸是怎么处理的,稍安勿躁,一步一步来分析下。
一个图片可以改变成任意尺寸,容器是80%:

<div>
  <img data-original="https://dummyimage.com/600x400/000/fff" alt="Norway">
</div>

不加任何属性:

img {}
div{
  width:80%;
  background-color:pink;
  text-align: center;
}

图片默认是不会缩放的,宽高是图片原尺寸,图片宽高高于容器时会溢出。

width:100%

img {
  width:100%;
}
div{
  width:80%;
  background-color:pink;
  text-align: center;
}

图片宽度随容器宽度缩放,图片宽高比不变,图片高度高于容器时会溢出。

max-width:100%

tips: max-height:100%效果是一样的

img {
  max-width:100%;
}
div{
  width:80%;
  background-color:pink;
  text-align: center;
}

图片图片宽度随容器宽度缩放,图片宽高比不变,图片高度高于容器时会溢出,
但缩放不会超过原图宽高。

二、解决方案

1、图片容器宽度百分比,高度自适应;图片等比例自适应

还是上面那个例子,图片任意尺寸,容器是80%:

<div>
  <img data-original="https://dummyimage.com/600x400/000/fff" alt="Norway">
</div>

容器高度无限制时

img {
   max-width: 100%;
/*   max-height: 400px; */
}
div{
  width:80%;
/*   min-height: 300px; */
  background-color:pink;
  text-align: center;
}

容器设置最大高度

img {
   max-width: 100%;
   max-height: 400px; 
}
div{
  width:80%;
/*   min-height: 300px; */
  background-color:pink;
  text-align: center;
}

容器设置最小高度

tips:此时若图片小于最小高度,图片垂直居中(采用flex布局)

img {
   max-width: 100%;
/*   max-height: 400px; */
}
div{
  width:80%;
  min-height: 300px;
  background-color:pink;
  display: flex;
  justify-content: center;
  align-items: center;
}

容器设置最大最小高度

img {
   max-width: 100%;
  max-height: 400px;
}
div{
  width:80%;
  min-height: 300px;
  background-color:pink;
  display: flex;
  justify-content: center;
  align-items: center;
}

2、图片容器宽高百分比;图片等比例自适应

<html>
  <head></head>
  <body>
    <div class='wrapper'>
      <div class='image'></div>
    </div>
  </body>
</html>
html,body{
  height: 100%;
}

.wrapper{
  width:80%;
  height:80%;
  background-color: pink;
}
.image{
  width: 100%;
  height: 100%;
  background-image: url('https://dummyimage.com/600x400/000/fff');
  background-size: contain;
  background-position: center center;
  background-repeat: no-repeat;
  background-color: #aaa;
}

3、图片容器宽高百分比;图片居中覆盖不缩放(显示不完整但不失真)

<html>
  <head></head>
  <body>
    <div class='wrapper'>
      <div class='image'></div>
    </div>
  </body>
</html>
html,body{
  height: 100%;
}

.wrapper{
  width:80%;
  height:80%;
  background-color: pink;
}
.image{
  width: 100%;
  height: 100%;
  background-image: url('https://dummyimage.com/600x400/000/fff');
  background-size: cover;
  background-position: center center;
}

4、使用picture元素或媒体查询,不同场景加载不同图片

如果<picture>元素与当前的<audio><video>元素协同合作将大大增强响应式图像的工作进程。它允许你放置多个source标签,以指定不同的图像文件名,进而根据不同的条件进行加载。

具体看:picturefill

查看原文

识得唔识得啊 收藏了文章 · 2019-10-11

js运行机制和事件循环

编译原理

任何 JavaScript 代码片段在执行前都要进行编译(通常就在执行前)。因此,JavaScript编译器首先会对 var a = 2; 这段程序进行编译,然后做好执行它的准备,并且通常马上就会执行它。

编译一般分为三步:

  • 分词/词法分析(Tokenizing/Lexing)
    这个过程会将由字符组成的字符串分解成(对编程语言来说)有意义的代码块,这些代

码块被称为词法单元(token)。例如,考虑程序 var a = 2;。这段程序通常会被分解成
为下面这些词法单元:var、a、=、2 、;。空格是否会被当作词法单元,取决于空格在
这门语言中是否具有意义。


  • 解析/语法分析(Parsing)

这个过程是将词法单元流(数组)转换成一个由元素逐级嵌套所组成的代表了程序语法
结构的树。这个树被称为“抽象语法树” (Abstract Syntax Tree,AST)。
var a = 2; 的抽象语法树中可能会有一个叫作VariableDeclaration 的顶级节点,接下
来是一个叫作Identifier(它的值是a)的子节点,以及一个叫作AssignmentExpression
的子节点。AssignmentExpression 节点有一个叫作 NumericLiteral(它的值是 2)的子
节点。


  • 代码生成

将 AST 转换为可执行代码的过程被称为代码生成。这个过程与语言、目标平台等息息
相关。
抛开具体细节,简单来说就是有某种方法可以将var a = 2; 的AST转化为一组机器指
令,用来创建一个叫作 a 的变量(包括分配内存等),并将一个值储存在a 中。

单线程

js引擎是单线程的,编译和执行js的线程只有一个。
nodejs和浏览器还有别的线程用于处理其它任务,如处理AJAX请求的线程、处理DOM事件的线程、定时器线程、读写文件的线程。

单线程所以有了事件循环。

消息队列和事件循环

函数调用形成一个栈帧,放入当前执行栈中,帧中包含了当前context需要的参数和局部变量。

堆栈队列.png

一个 JavaScript 运行时包含了一个待处理的消息队列。每一个消息都关联着一个用以处理这个消息的函数。

其它线程将消息放到消息队列,js线程通过事件循环过程去获取消息。

在事件循环期间的某个时刻,运行时从最先进入队列的消息开始处理队列中的消息。为此,这个消息会被移出队列,并作为输入参数调用与之关联的函数。

函数的处理会一直进行到执行栈再次为空为止;然后事件循环将会处理队列中的下一个消息。

异步中的微任务、宏任务

  • 宏任务(task):script,setTimeout,setInterval、setImmediate
  • 微任务(microtask):原生Promise(有些实现的promise将then方法放到了宏任务中)、process.nextTick、Object.observe(已废弃)、 MutationObserver

执行逻辑很简单,就是先清空当前context的micortask,再执行task

一个例子:

console.log('1');

setTimeout(function() {
    console.log('2');
    process.nextTick(function() {
        console.log('3');
    })
    new Promise(function(resolve) {
        console.log('4');
        resolve();
    }).then(function() {
        console.log('5')
    })
})

Promise.resolve().then(r=>console.log(16))

async function a1(){
    console.log('13')
    await console.log('14')
    console.log('15')
}

process.nextTick(function() {
    console.log('6');
})

new Promise(function(resolve) {
    console.log('7');
    resolve();
}).then(function() {
    console.log('8')
})

a1()

setTimeout(function() {
    console.log('9');
    process.nextTick(function() {
        console.log('10');
    })
    new Promise(function(resolve) {
        console.log('11');
        resolve();
    }).then(function() {
        console.log('12')
    })
})

查看原文

识得唔识得啊 发布了文章 · 2019-10-11

js运行机制和事件循环

编译原理

任何 JavaScript 代码片段在执行前都要进行编译(通常就在执行前)。因此,JavaScript编译器首先会对 var a = 2; 这段程序进行编译,然后做好执行它的准备,并且通常马上就会执行它。

编译一般分为三步:

  • 分词/词法分析(Tokenizing/Lexing)
    这个过程会将由字符组成的字符串分解成(对编程语言来说)有意义的代码块,这些代

码块被称为词法单元(token)。例如,考虑程序 var a = 2;。这段程序通常会被分解成
为下面这些词法单元:var、a、=、2 、;。空格是否会被当作词法单元,取决于空格在
这门语言中是否具有意义。


  • 解析/语法分析(Parsing)

这个过程是将词法单元流(数组)转换成一个由元素逐级嵌套所组成的代表了程序语法
结构的树。这个树被称为“抽象语法树” (Abstract Syntax Tree,AST)。
var a = 2; 的抽象语法树中可能会有一个叫作VariableDeclaration 的顶级节点,接下
来是一个叫作Identifier(它的值是a)的子节点,以及一个叫作AssignmentExpression
的子节点。AssignmentExpression 节点有一个叫作 NumericLiteral(它的值是 2)的子
节点。


  • 代码生成

将 AST 转换为可执行代码的过程被称为代码生成。这个过程与语言、目标平台等息息
相关。
抛开具体细节,简单来说就是有某种方法可以将var a = 2; 的AST转化为一组机器指
令,用来创建一个叫作 a 的变量(包括分配内存等),并将一个值储存在a 中。

单线程

js引擎是单线程的,编译和执行js的线程只有一个。
nodejs和浏览器还有别的线程用于处理其它任务,如处理AJAX请求的线程、处理DOM事件的线程、定时器线程、读写文件的线程。

单线程所以有了事件循环。

消息队列和事件循环

函数调用形成一个栈帧,放入当前执行栈中,帧中包含了当前context需要的参数和局部变量。

堆栈队列.png

一个 JavaScript 运行时包含了一个待处理的消息队列。每一个消息都关联着一个用以处理这个消息的函数。

其它线程将消息放到消息队列,js线程通过事件循环过程去获取消息。

在事件循环期间的某个时刻,运行时从最先进入队列的消息开始处理队列中的消息。为此,这个消息会被移出队列,并作为输入参数调用与之关联的函数。

函数的处理会一直进行到执行栈再次为空为止;然后事件循环将会处理队列中的下一个消息。

异步中的微任务、宏任务

  • 宏任务(task):script,setTimeout,setInterval、setImmediate
  • 微任务(microtask):原生Promise(有些实现的promise将then方法放到了宏任务中)、process.nextTick、Object.observe(已废弃)、 MutationObserver

执行逻辑很简单,就是先清空当前context的micortask,再执行task

一个例子:

console.log('1');

setTimeout(function() {
    console.log('2');
    process.nextTick(function() {
        console.log('3');
    })
    new Promise(function(resolve) {
        console.log('4');
        resolve();
    }).then(function() {
        console.log('5')
    })
})

Promise.resolve().then(r=>console.log(16))

async function a1(){
    console.log('13')
    await console.log('14')
    console.log('15')
}

process.nextTick(function() {
    console.log('6');
})

new Promise(function(resolve) {
    console.log('7');
    resolve();
}).then(function() {
    console.log('8')
})

a1()

setTimeout(function() {
    console.log('9');
    process.nextTick(function() {
        console.log('10');
    })
    new Promise(function(resolve) {
        console.log('11');
        resolve();
    }).then(function() {
        console.log('12')
    })
})

查看原文

赞 2 收藏 3 评论 0

识得唔识得啊 关注了用户 · 2019-10-11

Rachel @rachel_dev

产品设计一枚,初入前端深海,还请各位前辈多多指教<( ̄▽ ̄)/

关注 8

识得唔识得啊 发布了文章 · 2019-10-11

js的遍历

对象属性的遍历

ES6 一共有 5 种方法可以遍历对象的属性。

部署Symbol.iterator的数据结构的遍历

有iterator接口的除手动部署的外,包括数组、Set 和 Map 结构、某些类似数组的对象(比如arguments对象、DOM NodeList 对象)、后文的 Generator 对象,以及字符串。可以使用Array.from将类数组转换为数组。

es6使用for...of遍历有iterator接口的数据结构。

对象部署遍历器接口并不是很必要,因为这时对象实际上被当作 Map 结构使用,ES5 没有 Map 结构,而 ES6 原生提供了。

默认调用iterator的情况

  • 解构赋值
let set = new Set().add('a').add('b').add('c');

let [x,y] = set;
// x='a'; y='b'
let [first, ...rest] = set;
// first='a'; rest=['b','c'];
  • 扩展运算符
  • yield*
  • 任何接受数组作为参数的场合

遍历语法对比

  1. for循环
for (var index = 0; index < myArray.length; index++) {
  console.log(myArray[index]);}

比较麻烦

  1. Array.prototype.forEach()

没有办法中止或者跳出 forEach() 循环,除了抛出一个异常。如果你需要这样,使用 forEach() 方法是错误的。

若你需要提前终止循环,你可以使用:for循环,for...of,
Array.prototype.every/some/find/findIndex。

这些数组方法可以对数组元素判断,以便确定是否需要继续遍历:every(),some(),find(),findIndex()

  1. for...in

es5中的方法,用于遍历对象的键名,会遍历继承的属性。es6一般情况下使用for of。

查看原文

赞 0 收藏 0 评论 0

识得唔识得啊 收藏了文章 · 2019-10-11

抓取县市地图json数据

找了网上很多资源,不是数据太老数据有问题,就是要收费☹,于是自己抓取了一下阿里的数据

数据源

项目源码


数据都是异步获取写入,所以使用了axios,node版本是12.10.0
引入需要的资源:

import http from 'axios'
import fs from 'fs'

地址和地址拼接函数:

const baseUrl = 'http://datavmap-public.oss-cn-hangzhou.aliyuncs.com/areas/'

function ug(sort, code1, code2 = '00') {
    return baseUrl + sort + '/51' + code1 + code2 + '.json'
}

nodejs里面异步接口都是回调函数,在这里不太好用,转换成基于promise的:

function promisify(fn, t, argsNum = 3) { //t:this  args:参数个数
    return (...args) => {
        let arr = Array.from(args).slice(0, argsNum - 2)
        return new Promise((resolve, reject) => {
            fn.call(t, ...arr, args[argsNum - 2] || {}, (err, res) => {
                return err ? reject(err) : resolve(res)
            })
        })
    };
}

const rmdir = promisify(fs.rmdir, fs),
    mkdir = promisify(fs.mkdir, fs),
    appendFile = promisify(fs.appendFile, fs, 4)

promise更易用,代码可读性也高,相应的性能会下降一些。bluebird性能做过优化,相对promise会高一些,这里数据比较小就先自己搞一哈。

有两种获取方式,并发获取:

const children = [...Array(35).keys()]
const bound = [...Array(100).keys()]
bound.shift()
async function getConcurrent() {
    try {
        await rmdir('./map', {recursive: true})
        await mkdir('./map', {recursive: true})
    } catch (e) {
        console.log(e)
    }
    children.map(async (i) => {
        let code1 = i.toString().padStart(2, '0')
        try {
            let r = await http.get(ug('children', code1))
            await (async (r) => {
                await console.log('获取children/51' + code1 + '00成功')
                await appendFile('./map/51' + code1 + '00.json', JSON.stringify(r.data))
                console.log('保存children/51' + code1 + '00成功')
            })(r)
        } catch (e) {
        }
        bound.map(async (j) => {
            let code2 = j.toString().padStart(2, '0')
            try {
                let r = await http.get(ug('bound', code1, code2))
                await (async (r) => {
                    await console.log('###获取bound/51' + code1 + code2 + '成功')
                    await appendFile('./map/51' + code1 + code2 + '.json', JSON.stringify(r.data))
                    console.log('###保存bound/51' + code1 + code2 + '成功')
                })(r)
            } catch (e) {
            }
        })
    })
}

继发:

async function getSuccessive() {
    try {
        await rmdir('./map', {recursive: true})
        await mkdir('./map', {recursive: true})
    } catch (e) {
        console.log(e)
    }

    for (let i = 0; i < 35; i++) {
        let code1 = i.toString().padStart(2, '0')
        try {
            let r = await http.get(ug('children', code1))
            await (async (r) => {
                await console.log('获取children/51' + code1 + '00成功')
                await appendFile('./map/51' + code1 + '00.json', JSON.stringify(r.data))
                console.log('保存children/51' + code1 + '00成功')
            })(r)
        } catch (e) {
        }

        for (let j = 1; j < 100; j++) {
            let code2 = j.toString().padStart(2, '0')
            try {
                let r = await http.get(ug('bound', code1, code2))
                await (async (r) => {
                    await console.log('###获取bound/51' + code1 + code2 + '成功')
                    await appendFile('./map/51' + code1 + code2 + '.json', JSON.stringify(r.data))
                    console.log('###保存bound/51' + code1 + code2 + '成功')
                })(r)
            } catch (e) {
            }
        }
    }
}

并发明显比继发快很多
运行:

function run(option = false) {
    option ? getSuccessive() : getConcurrent()
}

run()

抓取其他地区的修改下数据和编号就可以,后续会抓取国家地理信息网的数据

查看原文

识得唔识得啊 发布了文章 · 2019-10-11

抓取县市地图json数据

找了网上很多资源,不是数据太老数据有问题,就是要收费☹,于是自己抓取了一下阿里的数据

数据源

项目源码


数据都是异步获取写入,所以使用了axios,node版本是12.10.0
引入需要的资源:

import http from 'axios'
import fs from 'fs'

地址和地址拼接函数:

const baseUrl = 'http://datavmap-public.oss-cn-hangzhou.aliyuncs.com/areas/'

function ug(sort, code1, code2 = '00') {
    return baseUrl + sort + '/51' + code1 + code2 + '.json'
}

nodejs里面异步接口都是回调函数,在这里不太好用,转换成基于promise的:

function promisify(fn, t, argsNum = 3) { //t:this  args:参数个数
    return (...args) => {
        let arr = Array.from(args).slice(0, argsNum - 2)
        return new Promise((resolve, reject) => {
            fn.call(t, ...arr, args[argsNum - 2] || {}, (err, res) => {
                return err ? reject(err) : resolve(res)
            })
        })
    };
}

const rmdir = promisify(fs.rmdir, fs),
    mkdir = promisify(fs.mkdir, fs),
    appendFile = promisify(fs.appendFile, fs, 4)

promise更易用,代码可读性也高,相应的性能会下降一些。bluebird性能做过优化,相对promise会高一些,这里数据比较小就先自己搞一哈。

有两种获取方式,并发获取:

const children = [...Array(35).keys()]
const bound = [...Array(100).keys()]
bound.shift()
async function getConcurrent() {
    try {
        await rmdir('./map', {recursive: true})
        await mkdir('./map', {recursive: true})
    } catch (e) {
        console.log(e)
    }
    children.map(async (i) => {
        let code1 = i.toString().padStart(2, '0')
        try {
            let r = await http.get(ug('children', code1))
            await (async (r) => {
                await console.log('获取children/51' + code1 + '00成功')
                await appendFile('./map/51' + code1 + '00.json', JSON.stringify(r.data))
                console.log('保存children/51' + code1 + '00成功')
            })(r)
        } catch (e) {
        }
        bound.map(async (j) => {
            let code2 = j.toString().padStart(2, '0')
            try {
                let r = await http.get(ug('bound', code1, code2))
                await (async (r) => {
                    await console.log('###获取bound/51' + code1 + code2 + '成功')
                    await appendFile('./map/51' + code1 + code2 + '.json', JSON.stringify(r.data))
                    console.log('###保存bound/51' + code1 + code2 + '成功')
                })(r)
            } catch (e) {
            }
        })
    })
}

继发:

async function getSuccessive() {
    try {
        await rmdir('./map', {recursive: true})
        await mkdir('./map', {recursive: true})
    } catch (e) {
        console.log(e)
    }

    for (let i = 0; i < 35; i++) {
        let code1 = i.toString().padStart(2, '0')
        try {
            let r = await http.get(ug('children', code1))
            await (async (r) => {
                await console.log('获取children/51' + code1 + '00成功')
                await appendFile('./map/51' + code1 + '00.json', JSON.stringify(r.data))
                console.log('保存children/51' + code1 + '00成功')
            })(r)
        } catch (e) {
        }

        for (let j = 1; j < 100; j++) {
            let code2 = j.toString().padStart(2, '0')
            try {
                let r = await http.get(ug('bound', code1, code2))
                await (async (r) => {
                    await console.log('###获取bound/51' + code1 + code2 + '成功')
                    await appendFile('./map/51' + code1 + code2 + '.json', JSON.stringify(r.data))
                    console.log('###保存bound/51' + code1 + code2 + '成功')
                })(r)
            } catch (e) {
            }
        }
    }
}

并发明显比继发快很多
运行:

function run(option = false) {
    option ? getSuccessive() : getConcurrent()
}

run()

抓取其他地区的修改下数据和编号就可以,后续会抓取国家地理信息网的数据

查看原文

赞 2 收藏 2 评论 0

识得唔识得啊 赞了回答 · 2019-01-07

cross-env 不起作用怎么办?

NODE_ENV脚本设置无效

场景如下:

//脚本
//cross-env模块下
cross-env NODE_ENV = dev && node app.js

//windows下
set NODE_ENV = dev && node app.js

问题分析:
问题出现在 '&&' 处

  • cross-env模块下,它划分出前后两个环境,后一句的环境没有设置到NODE_ENV变量,值为undefined;
//纠正,去掉&&
cross-env NODE_ENV = dev node app.js
  • windows下,NODE_ENV被设置成 'dev ',末尾带有一个空格
//纠正,去掉&&前的空格,不可以直接去掉&&
//因为去掉后,这句脚本就不能正确的被切分为两句来执行了,而直接是赋dev  node app.js给NODE_ENV
set NODE_ENV = dev&& node app.js

关注 5 回答 3

识得唔识得啊 回答了问题 · 2019-01-07

解决webpack条件引入文件

有一个提案:import(),可以条件引入,放入代码中

但与业务本身无关的不该加入到入口文件里,最好是放到webpack配置文件中中配置

关注 6 回答 4

识得唔识得啊 回答了问题 · 2019-01-02

解决JavaScript中遍历数组的方式:forEach 相对于 for 有什么优势◔ ‸◔?

我看上面的回答,有个很重要的都没有提到,循环里有异步函数时,for循环是继发执行的,foreach是并发的,具体可以自己试一下哈

async function tmd(i) {
  await new Promise((resolve)=>{setTimeout(()=>{
    console.log(i)
    resolve()
  },1000)})
}

let arr=[0,1,2]

async function forlog() {
  for(let i of arr){
    await tmd(i)
  }
}

async function felog() {
  arr.forEach(async function (i) {
    await tmd(i)
  })
}

关注 31 回答 16

认证与成就

  • 获得 17 次点赞
  • 获得 4 枚徽章 获得 0 枚金徽章, 获得 0 枚银徽章, 获得 4 枚铜徽章

擅长技能
编辑

(゚∀゚ )
暂时没有

开源项目 & 著作
编辑

(゚∀゚ )
暂时没有

注册于 2017-03-07
个人主页被 667 人浏览