20180708_ARTS_week02

ARTS 是耗子哥(左耳朵耗子)发起的一个活动。 A -- Algorithm 每周一道算法题 R -- Review 每周阅读并点评一篇英文技术文章 T -- Tip 每周学习一个技术技巧 S -- Share 每周分享一篇技术文章 坚持一年 :-) 这是我的第二周 ARTS

Algorithm

Add Two Numbers You are given two non-empty linked lists representing two non-negative integers. The digits are stored in reverse order and each of their nodes contain a single digit. Add the two numbers and return it as a linked list.

You may assume the two numbers do not contain any leading zero, except the number 0 itself.

Example

Input: (2 -> 4 -> 3) + (5 -> 6 -> 4) Output: 7 -> 0 -> 8 Explanation: 342 + 465 = 807.

/**
* Definition for singly-linked list.
* function ListNode(val) {
*     this.val = val;
*     this.next = null;
* }
*/
/**
 * @param {ListNode} l1
 * @param {ListNode} l2
 * @return {ListNode}
 */
var addTwoNumbers = function (l1, l2) {
    var carry = 0; // 进位

    var item = new ListNode();  // 这两行分开写,beats 98.95%
    var cur = item;             // 如果用 var item = cur = new ListNode(); 则会变慢,beats 88.72% 

    while(l1 || l2 || carry) { // 加 carry 是因为最后要计算都为 null,但是有进位的情况
        var val1 = l1 ? l1.val : 0;
        var val2 = l2 ? l2.val : 0;

        var val = val1 + val2 + carry;
        cur.val = val % 10;
        carry = Math.floor(val / 10);

        l1 && (l1 = l1.next);
        l2 && (l2 = l2.next);

        if (l1 || l2 || carry) { // 判断是否要加下一个节点
            cur.next = new ListNode();
            cur = cur.next
        }
    }

    return item
};

这个题目主要就是把进位分开来算,不要把两个单链表全部转回数字然后想加再转回单链表。

我这里有个比较不好的地方是同一种判断条件用了两次,暂时还没想到合并的方法,能去掉就更好了。

程序中的状态是你程序变得复杂难维护的直接原因。

Review

How you can improve your workflow using the JavaScript console

JavaScript 调试中 console.log 是最常用的,作者在这个基础上,又另外介绍了几个方法,挑几个平常没注意到又挺有用的记录一下。

console.group / console.groupEnd

function doSomething(obj) {
 console.group('doSomething Profile')
 const _data = new Date()
 console.log('evauating data:', _data)
 const _fullName = `${obj.firstName} ${obj.lastName}`
 console.log('fullName:', _fullName)
 consst _id = Math.random(1)
 console.log('id:', _id)
 console.groupEnd()
}

doSomething({'firstName':'Riccardo', 'lastName':'Canella'})

使用 console.groupconsole.groupEnd 可以把中间的 log 有个分组,也挺方便管理的。

console.table

const mySocial = {
 facebook: true,
 linkedin: true
}

console.table(mySocial, ["Socials", "I'v an account"])

会把 json 数据用一个表格输出,并且可以自己设置表头,看数据的时候挺实用。

console.trace / console.assert

function lesserThan(a,b) {
 console.assert(a < b, {'message':'a is not lesser than b','a':a,'b':b})
}
lesserThan(6,5)
console.trace('End')

JavaScript 的语法里面一直没看到有断言相关的内容,看到很多单元测试框架都是提供一个断言方法。console.assert 可以一定程度上充当断言的功能,如果错了会在控制台打印信息和堆栈,这个还是挺有用,有时候系统报错的时候打出的错误堆栈内容非常多,常常不知道是哪一步出错了,特别是用了一些框架类库,层层深入。用了 console.assert 可以更主动一点,当不满足条件的时候就打印信息和堆栈。

console.trace 可以直接打印现有的堆栈。


除此之外,作者还讨论了 console.log 滥用的问题。前端以前缺少一些必要的机制去避免 log 到处打的问题,可能你本地调试的 log 一不小心就提交发了外网。近年随着前端工程化的完善,开始有一些处理机制,比如 production 版本的构建和本地 dev 版本的分离,可以在 production 版本中做 log 去除,代码压缩等工作,不过还是比不上其它更完善语言。

Tip

分享一下 ES6 中使用 async/await 优化异步代码。

先设定一个场景,多个图片异步加载,都加载完之后触发回调函数。 在 ES5 下,基本思路就是做一个计数器,每次 image 触发 onload 就加一,达到次数后触发回调函数。

var count = 0,
     imgs = [];

function loadImgs(imgList, cb) {
    imgList.forEach(function(url, i) {
        imgs[i] = new Image();
        imgs[i].onload = function() {
            if( ++count === imgList.length) {
                cb && cb()
            }
        }
        imgs[i].src = url;
    })
}

// 调用
loadImgs(["xxx/a.png","xxx/b.png"],function() {
    console.log("开始干活");
})

这样做基本功能是能满足的,但是这种回调的方式跳来跳去,代码显得比较混乱。尤其是当异步代码有嵌套的时候,简直痛不欲生。

ES6 下可以用 Promise 和 async/await 来优化代码,我们先用 async/await 改造一版。

async function loadImgs(imgList, cb) {

    console.log("start")
    for( var i =0; i<imgList.length; i++) {
        await imgLoader(imgList[i], i);
        console.log("finish"+i)
    }
    cb();
}

async function imgLoader(url, num){
    return new Promise((resolve, reject) => {
        console.log("request"+num)

        setTimeout(resolve, 1000);
        // let img = new Image();
        // img.onload = () => resolve(img);
        // img.onerror = reject;

        console.log("return"+num)
    })
}

loadImgs(["xxx/a.png","xxx/b.png"],function() {
    console.log("开始干活");
})

运行的结果是:

start
request0
return0
finish0
request1
return1
finish1
开始干活

这里通过一个 for 循环,我们执行了多次 imgLoader 函数,我们期望的是 async/await 改造后是异步的,但实际运行的结果却是同步的。 request0 finish 之后,request1 才发出。

这样写其实是想当然的掉了异步的坑,事实上,async/await 并没有什么神器的魔力,能让加了它们的代码就能变成异步。async/await 其实是一个语法糖,让你可以把大段的回调代码写成同步的形式。本质上是为了解决回调过多,可读性差的问题。 所以你要理解,await 后面的都是回调代码,那你这样多个图片加载用循环的方式其实就是每次执行完一个加载就回调开始执行下一个加载,自然就是同步了。

上面那个场景,正确的做法是使用 Promise.all 加载完之后返回,因为我们预期的就是在全部加载完之后才执行回调。

async function loadImgs(imgList){
    let proList = [];
    for(var i=0; i<imgList.length; i++ ){
        let pro = new Promise((resolve, reject) => {
            console.log("request"+i)
            setTimeout(resolve, 2000);
            console.log("return"+i)
        })
        proList.push(pro)
    }

    return Promise.all(proList)
            .then( ()=>{
                console.log("finish all");
                return Promise.resolve();
            })
}

async function entry(imgList, cb) {
    await loadImgs(imgList);
    cb();
}

entry(["xxx/a.png","xxx/b.png"], function(){
    console.log("开始干活")
})

会看到一开始就立马打印出

request0
return0
request1
return1

过了两秒之后,才打印出 finish all


async/await 和函数回调的形式都可以借助 Promise 来优化,不同的是,async/await 是自动挡,函数回调是手动挡,而 Promise 是发动机

Share

这周遇到挺多事情的,心里乱乱的,很多事情也还没想清楚,就分享点做了两周 ARTS 的感受吧。

我做 ARTS 的节奏是周一到周四每天做一个字母,周五一般是 buffer,周末主要是把几个东西整理一下,看是否有补充的。

这样每天压力不会太大,又能保证一定的紧张感,暂时也能坚持下去。

ARTS 整体来说,我最喜欢的是 A 和 R。

毕业几年之后做的又是前端方面的工作,基本和算法不怎么沾边,这两周完成了算法题,又感受到了编程之美,挺开心的。通常我会先看看算法题的要求,然后通勤路上就脑子里面大概想一想,再用下班之后的时间代码实现一下,这样的好处是利用了通勤的时间,深圳还是挺堵车的,我花在上班单程大概 40 分钟,摇摇晃晃不适合阅读,引擎声也影响听专栏,用脑子,放飞思绪倒是挺好的。

至于 R,强迫自己看英文文章对英语阅读能力的提升还是有点好处的,阅读英文文章对提升视野也有一定的帮助。往往没有用更好的方法,是因为你不知道有更好的方法,甚至是不知道自己不知道有更好的方法。不过由于工作的关系,现在看的英文文章还是偏向前端方面比较多,后面要慢慢扩大一下阅读面。

总体来说 ARTS 是一个非常不错的活动,但是有一点需要注意的,空闲时间不要只做 ARTS,该系统的学习什么技术,看看书,练习练习还是必要的,ARTS 是一个通用的锻炼途径,我们还需要根据自己的实际情况,规划自己的提升计划,不要用战术上的勤奋掩盖战略上的懒惰。

共勉。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 异步多图加载这件小事儿(Promise与async)

    日常开发过程中,时不时会遇到要同时预加载几张图片,并且等都加载完再干活的情况,结合 Promise 和 async/await 代码会优雅很多,但也容易遇到坑,...

    Bob.Chen
  • 20180930_ARTS_week14

    想到这个的思路是因为解的过程中,发现如果遇到左边的,需要存起来,后面可能有用(类似入栈),遇到右边的,需要比对前一个值,并且比完如果匹配就没用了(这类似出栈)。...

    Bob.Chen
  • CSS3动画-抛物线运动

    今天来说下CSS3动画,目标是让一个方块做抛物线运动。主要用到的CSS3属性有animation,transform,@keyframes,transition...

    Bob.Chen
  • 我理解的JavaScript预编译

    JavaScript执行过程首先先语法分析,就是分析一遍代码有没有语法错误,解析期间不会执行代码。接着就开始预编译,预编译完了就开始一行一行执行代码。

    wade
  • 探究{ a = 1; function a(){} }和{ function b(){}; b = 1 }

    相信大部分人都了解了,这里再重复啰嗦一下。js是解析执行的,变量提升是js中执行上下文的工作方式。变量声明和函数声明在编译阶段会被提前。

    lhyt
  • react入门(四):组件生命周期

    componentWillReceiveProps shouldComponentUpdate componentWillUpdate componentDid...

    柴小智
  • 从Generator到Async function

    为什么说Async function是从Promise,Generator一路走来的?

    ayqy贾杰
  • 10分钟了解JS堆、栈以及事件循环的概念

    其实一开始对栈、堆的概念特别模糊,只知道好像跟内存有关,又好像事件循环也沾一点边。面试薄荷的时候,面试官正好也问到了这个问题,当时只能大方的承认不会。痛定思痛,...

    用户2356368
  • 微任务与宏任务

    众所周知,JavaScript是基于事件循环而运行的,微任务与宏任务是事件循环中重要概念。自node火起来后,这个知识点就成了面试官压轴大题,所以我们必须要会。

    kai666666
  • 让我印象深刻的javascript面试题

    对于一个web前端来说,面试的时候,难免会遇到javascript的面试题。就我自己而言。有几道面试题,有些是我面试遇到的,有些是在网上看到的,但是都印象深刻。...

    守候i

扫码关注云+社区

领取腾讯云代金券