赖皮喵

赖皮喵 查看完整档案

填写现居城市  |  填写毕业院校  |  填写所在公司/组织填写个人主网站
编辑
_ | |__ _ _ __ _ | '_ \| | | |/ _` | | |_) | |_| | (_| | |_.__/ \__,_|\__, | |___/ 该用户太懒什么也没留下

个人动态

赖皮喵 收藏了文章 · 今天 09:24

通俗浅显的理解Promise中的then

Promise,ES6中定义的规范,不会使用Promise,都不敢说自己用过ES6,大部分介绍Promise的规范的文章对于新手小白来说看得云里雾里,且并不是通俗易懂。本文通过实例介绍讲述Promise中then的的最通俗应用理解,代码建立在不出现异常的情况的操作下,不严谨之处,请以官方规范为标准。

先看一下下面4个Promise到底有什么区别呢?

func().then(function () {
  return cb();
});
 
func().then(function () {
  cb();
});
 
func().then(cb());
 
func().then(cb);

如果你知道答案,以下内容你可以不用继续。

上面的代码过于简单,运行时话需要稍微进行一点扩展,每个方法中都打印出promise上一步的调用值,为了方便我给每个方法加了一个下标输出,分别是1、2、3、4。

let func = function() {
    return new Promise((resolve, reject) => {
        resolve('返回值');
    });
};

let cb = function() {
    return '新的值';
}

func().then(function () {
    return cb();
}).then(resp => {
    console.warn(resp);
    console.warn('1 =========<');
});

func().then(function () {
    cb();
}).then(resp => {
    console.warn(resp);
    console.warn('2 =========<');
});

func().then(cb()).then(resp => {
    console.warn(resp);
    console.warn('3 =========<');
});

func().then(cb).then(resp => {
    console.warn(resp);
    console.warn('4 =========<');
});

不卖关子,直接看结果

clipboard.png

首先要明白Promise中then方法会干什么事情!

官方文档是这样定义的:

一个 promise 必须提供一个 then 方法以访问其当前值、终值和据因。

promise 的 then 方法接受两个参数:

promise.then(onFulfilled, onRejected) Todo:这里只介绍onFulfilled,所以删除了关于onRejected的规范定义

onFulfilled 和 onRejected 都是可选参数。

如果 onFulfilled 不是函数,其必须被忽略
如果 onFulfilled 是函数:

当 promise 执行结束后其必须被调用,其第一个参数为 promise 的终值
在 promise 执行结束前其不可被调用
其调用次数不可超过一次

用通(ren)俗(hua)的话来说:
then方法提供一个供自定义的回调函数,若传入非函数,则会忽略当前then方法。
回调函数中会把上一个then中返回的值当做参数值供当前then方法调用。
then方法执行完毕后需要返回一个新的值给下一个then调用(没有返回值默认使用undefined)。
每个then只可能使用前一个then的返回值。

直观的图:
clipboard.png

有了上面的定义我们带着三个疑问来回答问题:

  1. 上一个then中传入了回调函数吗?
  2. 上一个then中提供了返回值吗?
  3. 若上一个then中若提供了返回值,返回了什么?

执行第一个方法:

func().then(function () {
    return cb();
}).then(resp => {
    console.warn(resp);
    console.warn('1 =========<');
});

clipboard.png

function () {
    return cb();
}

显而易见,是传入了回调函数的
回调函数中把cb执行后的返回值当做then中的返回值,所以输出了“新的值”;

执行第二个方法:

func().then(function () {
    cb();
}).then(resp => {
    console.warn(resp);
    console.warn('2 =========<');
});

clipboard.png

function () {
    cb();
}

then回调方法,只是执行了cb方法,并没有return值,定义中讲过若then没有返回值,提供给下一个then使用的参数就是undefined,所以打印出来的是undefined;

执行第三个方法:

func().then(cb()).then(resp => {
    console.warn(resp);
    console.warn('3 =========<');
});

clipboard.png

func().then(cb())

then中cb()执行后返回的并不是一个函数,在Promise规范中会自动忽略调当前then,所以会把func中的返回值供下一个then使用,输出了“返回值”

执行第四个方法:

func().then(cb).then(resp => {
    console.warn(resp);
    console.warn('4 =========<');
});

clipboard.png

func().then(cb)

第一个方法在回调内部返回cb执行后的值,第四个方法则直接把cb当做回调,第一个方法与第四个方法异曲同工之妙,所以也输出了“新的值”。

题目出处:http://web.jobbole.com/82601/
Promise规范:https://promisesaplus.com/

查看原文

赖皮喵 回答了问题 · 9月19日

vue2.6.12源码调试报错

解决了,这是我把rollup-plugin-alias升级到最新版本2.2.0后执行npm run dev报的错,因为我直接把源码拉下来rollup-plugin-alias的版本是^1.3.1,执行npm run dev出现不能加载config这个js的问题,网上是说rollup-plugin-alias插件在window下的bug,于是我升级到最新没有出现不能加载的问题,但是访问页面出现了一系列新的问题,怎么都解决不了,最后发现是我的文件夹有中文名字,最后rollup-plugin-alias还是用的^1.3.1这个版本

关注 2 回答 1

赖皮喵 关注了问题 · 9月14日

vue2.6.12源码调试报错

小白求大神指点,vue 源码调试按照网上的教程修改

package.json:
"dev": "rollup -w -c scripts/config.js --environment TARGET:web-full-dev --sourcemap",

scripts/config.js:
sourceMap: true // 为了更清晰调试代码,建议你开启

examples/commits/index.html:
<script data-original="../../dist/vue.js"></script>

然后运行examples/commits/index.html出现错误
image
image

查看vue.js 这些参数全是undefined

vue版本为2.6.12

关注 2 回答 1

赖皮喵 提出了问题 · 9月11日

vue2.6.12源码调试报错

小白求大神指点,vue 源码调试按照网上的教程修改

package.json:
"dev": "rollup -w -c scripts/config.js --environment TARGET:web-full-dev --sourcemap",

scripts/config.js:
sourceMap: true // 为了更清晰调试代码,建议你开启

examples/commits/index.html:
<script data-original="../../dist/vue.js"></script>

然后运行examples/commits/index.html出现错误
image
image

查看vue.js 这些参数全是undefined

vue版本为2.6.12

关注 2 回答 1

赖皮喵 关注了问题 · 9月4日

Vue源码在windows下运行npm run dev 报错

如题,这个问题要如何解决?

报错信息:bundling...
Error: Error: Could not load E:testvue_componentvuesrccore/config (imported by E:testvue_componentvuesrcplatformswebentry-runtime-with-compiler.js): ENOENT: no such file or directory, open 'E:testvue_componentvuesrccoreconfig'
用cross-env改写也没有成功,球赐教!

关注 3 回答 1

赖皮喵 关注了用户 · 8月26日

嘻倪孢 @xybao

快乐就好!

关注 11

赖皮喵 赞了文章 · 7月3日

vue项目实现按需加载的3种方式:vue异步组件、es提案的import()、webpack的require.ensure()

1. vue异步组件技术

  • vue-router配置路由,使用vue的异步组件技术,可以实现按需加载。

但是,这种情况下一个组件生成一个js文件。
举例如下:

        {
            path: '/promisedemo',
            name: 'PromiseDemo',
            component: resolve => require(['../components/PromiseDemo'], resolve)
        }

2. es提案的import()

vue官方文档:路由懒加载(使用import())

  • vue-router配置路由,代码如下:
// 下面2行代码,没有指定webpackChunkName,每个组件打包成一个js文件。
const ImportFuncDemo1 = () => import('../components/ImportFuncDemo1')
const ImportFuncDemo2 = () => import('../components/ImportFuncDemo2')
// 下面2行代码,指定了相同的webpackChunkName,会合并打包成一个js文件。
// const ImportFuncDemo = () => import(/* webpackChunkName: 'ImportFuncDemo' */ '../components/ImportFuncDemo')
// const ImportFuncDemo2 = () => import(/* webpackChunkName: 'ImportFuncDemo' */ '../components/ImportFuncDemo2')
export default new Router({
    routes: [
        {
            path: '/importfuncdemo1',
            name: 'ImportFuncDemo1',
            component: ImportFuncDemo1
        },
        {
            path: '/importfuncdemo2',
            name: 'ImportFuncDemo2',
            component: ImportFuncDemo2
        }
    ]
})

3. webpack提供的require.ensure()

  • vue-router配置路由,使用webpack的require.ensure技术,也可以实现按需加载。

这种情况下,多个路由指定相同的chunkName,会合并打包成一个js文件。
举例如下:

        {
            path: '/promisedemo',
            name: 'PromiseDemo',
            component: resolve => require.ensure([], () => resolve(require('../components/PromiseDemo')), 'demo')
        },
        {
            path: '/hello',
            name: 'Hello',
            // component: Hello
            component: resolve => require.ensure([], () => resolve(require('../components/Hello')), 'demo')
        }

项目路由配置文件:https://github.com/cag2050/vu...

查看原文

赞 103 收藏 103 评论 10

赖皮喵 发布了文章 · 7月3日

h5和app交互

1、h5调用app的方法或者传值

// Android:
window.Android.方法名(参数)
// ios
window.webkit.messageHandlers.方法名.postMessage(参数)

2、app处理完后回调(向h5传值)

// 自定义一个事件,供app调用
window.供app调用的方法名 = function (data) {
    let event = new CustomEvent('自定义的事假名', {
      'detail': {
        data: data // app传递过来的值
      }
    })
    let dom = document.querySelector('挂载自定义事件的元素id')
    dom.dispatchEvent(event)
  }

3、例子(这里是h5调用app的扫码功能,将扫码结果回传,基于vue开发)

// html
<img class="icon-code" data-original="../../assets/icon-code.png" alt="" id="sweepBtn" @click.stop="sweepCode" @SweepData="sweep($event)">

// js

// 调取原生扫码接口
 sweepCode () {
      this.$store.state.isAndroid ? window.Android.sweepToApp('start') : window.webkit.messageHandlers.sweepToApp.postMessage('start')
 }
    
// app处理结果回调
sweep (e) {
   console.log(e.detail.data) // app传递结果
},

// 供app调用传值的全局方法(注意需要挂载到window app才调用得到)
window.SweepData = function (data) {
    let event = new CustomEvent('SweepData', {
      'detail': {
        data: data
      }
    })
    let dom = document.querySelector('#sweepBtn')
    dom.dispatchEvent(event)
}

以上为自己的使用记录,有更好的方法或者我有不对的地方,欢迎指正

查看原文

赞 1 收藏 1 评论 0

赖皮喵 赞了文章 · 7月3日

for循环与事件的i传值问题(5种解决方法)

希望可以实现点击哪个就打印出对应的顺序

<ul>
  <li>第0个</li>
  <li>第1个</li>
  <li>第2个</li>
  <li>第3个</li>
  <li>第4个</li>
</ul>

错误实现:

注意此处使用的var i=0, var是可以被重复定义的,最后执行了i++,根据垃圾回收机制,当点击事件发生的时候,i已经变成5了,所以不管点击哪个li,打印的都是5

window.onload=()=>{
  const list = document.querySelectorAll('li')
  for (var i=0; i<list.length; i++){
    list[i].onclick = ()=>{
        console.log(i)
    }
  }
}

正确实现:

方法一:给每个li添加自定义属性

window.onload=()=>{
  const list = document.querySelectorAll('li')
  for (var i=0; i<list.length; i++){
    list[i].index = i
    list[i].onclick = function (){
        console.log(this.index)
    }
  }
}

方法二:自执行函数,并利用作用域的关系,定义函数把i传进来,并进行自动调用

for (var i=0; i<list.length; i++){
  // (function(i){})表示定义,i表示形参;(i)表示调用,i表示实参
  (function(i){
    list[i].onclick = function(){
      console.log(i)
    }
  })(i)
}

方法三:ES6中的let,let应用于块级作用域,块级作用域以大括号划分
let不会被垃圾回收机制回收,var为什么会被回收?因为var声明的变量会被覆盖,而let不能被覆盖,就会被存下来。

for (let i=0; i<list.length; i++){
    list[i].onclick = ()=>{
        console.log(i)
    }
}

方法四:利用for循环的方法:filter、forEach、map(注意全都是ES5的,不是ES6的)

// 注意此处有一个兼容性问题,li是类数组,兼容性好的浏览器可以直接使用这三个方法,但是兼容性不好的不能直接用
// 为保证稳妥,最好转成真正的数组
const newArr = [].slice.call(list) // 或者const newArr = Array.prototype.slice.call(list), []是Array的原型
console.log(list) // NodeList(5) [li, li, li, li, li]      NodeList是dom中的一个对象
console.log(newArr) //  [li, li, li, li, li]       被转成了真正的数组
newArr.forEach((value,index)=>{
  value.onclick=function(){
    console.log(index)
  }
})
newArr.filter((value,index)=>{
  value.onclick=function(){
    console.log(index)
  }
})
newArr.map((value,index)=>{
  value.onclick=function(){
    console.log(index)
  }
})

方法五:ES6中给Array的from方法

Array.from(list, function(value, index){
  value.onclick=function(){
    console.log(index)
  }
})
查看原文

赞 2 收藏 0 评论 0

赖皮喵 赞了文章 · 2019-02-18

【git】前端使用git分支的开发流程

一、先讲背景

git分支主要有以下:
主分支:master,保证所有已发布到生产环境的分支都已merge到master,并且,新分支比如从master创建
日常分支:daily,本地开发和测试环境使用,保证所有的已上生产和发布测试的分支都已merge到daily
其他分支:版本分支或bug分支,从master拉取,并在merge到master后删除
前端团队采用如下开发流程:
(接到版本需求后,假设不需要后端接口配合,或后端接口已开发完毕)

二、开发阶段

第一阶段(本地开发+测试环境阶段)

step1:master创建一个新分支featrue-2019-2,此为版本分支,并拉取到本地,使用SwicthHosts将本地开发环境映射到日常环境,也称测试环境,在本地开发调试
step2:本地开发后,使用sourcetree保存并提交到远程featrue-2019-2分支,你使用git命令也是一样
step3:拉取日常环境分支daily,并将featrue-2019-2 merge到 daily
step4:使用JenKins(日常环境账号)登录后构建daily分支,表示对daily的代码执行npm run
build+push,构建成功后通知测试人员 step5:若测试有问题,修改后,重复step2、step3、step4,直到测试通过

第二阶段(预发阶段)

step1:merge master 到 featrue-2019-2,保证featrue-2019-2已包含所有的生产代码
step2:使用JenKins(预发环境账号)登录后构建featrue-2019-2分支,构建成功后通知测试
step3:若测试有问题,检查测试环境是否也有此问题,若有,则要返回第一阶段的step2

第三阶段(生产阶段)

step1:此分支发预发后,若有别的分支发了生产,则需要执行merge master 到
featrue-2019-2,保证featrue-2019-2已包含所有的生产代码
step2:使用JenKins(生产环境账号)登录后构建featrue-2019-2分支,构建成功后通知测试
step3:featrue-2019-2 merge 到 master,并删除featrue-2019-2,
step4:若测试有问题,汇总问题,从master拉取bug分支,例如可命名为featrue-2019-2-bug,从第一阶段开始,开启一个新的版本开发

三、分支原则

1、保证master分支是唯一主分支
2、所有版本分支,所有需求,所有代码,必须按“照构建日常——>构建预发——>构建生产”的顺序执行
3、所有版本分支只开发此版本相关内容,不可混合其他版本需求开发
4、分支发布生产后,必须尽快merge到master
5、分支的生命周期,从master上拉取开始,到merge到master以后结束,一个分支尽量只使用一次,即merge到master以后就删除
6、不要频繁发布生产,日常和预发不受限制

四、预发环境的必要性

以前的公司,只有测试/预发环境和正式/生产环境,来到这家公司后,才了解到预发环境的必要性。
测试环境,用来测试代码没有问题,但是测试环境里都是测试数据,和真实数据差别很大,大家都知道,对于前端来说这些数据的不同会造成特殊情况存在,例如测试环境的数据不合法。
而预发环境则是真实数据,基本上用户在预发环境的所见,99%等同于在生产环境的所见,所以,必要性可想而知。

查看原文

赞 2 收藏 1 评论 0

认证与成就

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

擅长技能
编辑

(゚∀゚ )
暂时没有

开源项目 & 著作
编辑

(゚∀゚ )
暂时没有

注册于 2016-11-21
个人主页被 362 人浏览