pretty code

顯示具有 Javascript 標籤的文章。 顯示所有文章
顯示具有 Javascript 標籤的文章。 顯示所有文章

2019年12月19日 星期四

Chrome Extension + Export Excel

之前寫的 The books list 小工具,可以幫忙把網頁上顯示的購買書籍書名 parsing 出來,以方便後續使用,目前支援 Readmoo 舊版書櫃,Kobo 以及 Google Play Books。另外,Google Play Books 的書購買的不夠多,故不確定分頁機制如何,無法處理。

原本是直接將書名顯示在 Web 視窗,但似乎還是有點麻煩,雖然我現在也懶得另外整理清單了,前天趁著測試的空檔,使用 SheetJS 這個純 javascript 套件,便順利的產出了 Excel 2007 格式。

另外,調整格式等功能需要 Pro 版本才行,但一般使用已經夠用。

如果想自己改 Community 版本的話,只要 follow 他的 License,應該也可以自行加上 Style 等功能,這個可以找其他語言的 Open Source 專案,便知道如何比照辦理。

或許也可以使用 Golang 的任一專案,來個 Golang -> WebAssembly -> Javascript 乾坤大挪移也說不定?

2019年5月31日 星期五

javascript async 小陷阱

有時候真的對 javascript 沒好氣。

原本以為算是已經掌握了 async / await 的用法,沒想到還是會遇到原本沒想過的 case。

一般來說,想要用 async 就是想要避免 callback 寫法,但如果在 async 裡面使用非同步語法會怎樣?

嚴格來說是沒有使用 await 配合非同步。

底下的例子就告訴我們結果。

原因是 javascript 會自動幫我們回傳 1 個 promise,所以 setTimeout 還未倒數完,程式已回傳結果。


async function test() {
    setTimeout(() => {
        console.log('after 2 seconds');
        return Promise.resolve('good');
    }, 2000);
}

test().then((res) => {
    console.log(res);
}).catch(err => {
    console.log(err);
});

結果

undefined
after 2 seconds

2019年1月29日 星期二

ES7 Async performance 陷阱

在有了 Async / Await 的語法糖加持之後
感覺 Node.js 的世界突然美好了起來

終於可以用比較直覺的角度去寫程式
特別是那些習慣寫 C, Java, Python 等的人

但是在方便之餘
還是要特別小心 await 的使用情境
以避免造成效能上的問題

在下列例子中
testAsync1 會比 testAsync2 有更好的效能

因為在 testAsync1 中
我們會先用一個變數 promise2 去承接 Promise
此時,這個 Promise 裡面的操作有機會先執行
等到 await promise1 時,promise2 就差不多執行完畢 (秒數一樣)
故在 await promise2 時,promise2 應該就是一個 ready 的狀態 (ok or failed)

而在 testAsync2 中
因為我們少了那個中間變數
故在 await 時,至少一定要等待 3 秒

這就因此造成了 2 者間的差異

function getPromise() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve('ok');
        }, 3000);
    });
}

async function testAsync1() {
    var date1 = new Date();

    var promise1 = getPromise();
    var promise2 = getPromise();

    var res;
    res = await promise1;
    res = await promise2;

    console.log(res, new Date() - date1);
    return Promise.resolve();
};

async function testAsync2() {
    var date1 = new Date();

    var res;
    res = await getPromise();
    res = await getPromise();

    console.log(res, new Date() - date1);
    return Promise.resolve();
};

testAsync1();
testAsync2();

執行結果如下

ok 3002
ok 6001

2018年11月2日 星期五

Javascript 非同步 pattern

還沒有 Promise, asyc / await 前
在撰寫非同步程式時
其實 code 的邏輯不太好看
又容易會有 callback hell 的問題

今天想了一下,其實可以用以下概念來處理此類問題

我們以常見的從資料庫撈資料來看
大概注意幾個重點即可

1. 在 function 內寫出一連串要做事的 function and callback
2. 上述 function 不要寫成變數,否則會有 undefined 的問題(hoist)
3. 相關的 function 可以照執行順序寫好,方便閱讀


function getDataFromDB(callback) {
    console.log("start connect to DB");
    connectDB(connectDBCB);

    function connectDB(cb) {
        setTimeout(() => {
            console.log("connect to DB done \n");
            cb(null, "fake handle");
        }, 2000);
    }

    function connectDBCB(err, conn) {
        console.log("start get data");
        getData(conn, getDataCB);
    }

    function getData(conn, cb) {
        setTimeout(() => {
            console.log("get data done \n");
            cb(null, conn);
        }, 2000);
    }

    function getDataCB(err, conn) {
        setTimeout(() => {
            console.log("prepare data to back");
            callback(err, [1, 2, 3]);
        }, 2000);
    }
}

getDataFromDB((err, data) => {
    console.log(err, data);
});

2018年11月1日 星期四

Javascript substr

以前再取子字串時都習慣使用 substr
今天才知道這個 function 不算是標準的 ECMAScript Spec(僅在附錄)
故建議是不要使用 substr
可以用 substring or slice 來代替

Annex B (normative)
Additional ECMAScript Features for Web Browsers

The ECMAScript language syntax and semantics defined in this annex are required when the ECMAScript host is a web browser. The content of this annex is normative but optional if the ECMAScript host is not a web browser.

NOTE This annex describes various legacy features and other characteristics of web browser based ECMAScript implementations. All of the language features and behaviours specified in this annex have one or more undesirable characteristics and in the absence of legacy usage would be removed from this specification. However, the usage of these features by large numbers of existing web pages means that web browsers must continue to support them. The specifications in this annex defined the requirements for interoperable implementations of these legacy features.

These features are not considered part of the core ECMAScript language. Programmers should not use or assume the existence of these features and behaviours when writing new ECMAScript code. ECMAScript implementations are discouraged from implementing these features unless the implementation is part of a web browser or is required to run the same legacy ECMAScript code that web browsers encounter.

Javascript 浮點數轉整數

Javascript 的數字類型是 64 位元的浮點數

以前在轉 C code 時
遇到類似 3/2 的語法都用 parseInt(3/2) 來取代

正規來說,應該要用 Math.floor(3/2)
也讓不懂 Javascript 的人比較好懂 code 的意義

2018年10月31日 星期三

Javascript variable hoisting

以前只是大概知道
並沒有認真搞懂

使用 var 宣告的變數 scope
是在最接近它的 function 裡

故在 a 處,因為 variable hoisting 的關係
x 變數是存在的,但是仍未賦值
故印出來的結果是 undefined

假設我們沒有宣告 var x = 2
則 a 處就會觸發 "ReferenceError: x is not defined"
function foo() {
    console.log(x);      // a

    var x = 2;

    console.log(x);
}

foo();

2018年10月16日 星期二

Javascript async / await 速成



01. await 後面接的是 1 個 Promise,一定會等待此 Promise 狀況 ready 

02. new Promise((resolve, reject) => {
        // ok 
        resolve(xx);
        return;
        
        // error
        reject(new Error("xxx"));
    });

03. async function 一定要回傳 1 個 Promise
    async function asyncXXX(xx) {
        try {
            
            // return value, 會被隱性轉成 Promise
            return 1;
            
            // Use static method
            return Promise.resolve(xx);
            
        } catch(err) {
            return Promise.reject(err);        
        }
    }
    
    asyncXXX(xx).then((xx) => {
        console.log(xx);
        
        // 如果有 return Promise 會形成 Promise chain
        return 1;    
        return new Promise(...);
    }).catch((err) => {
        // err is Error type
        console.log(err.message);
    });

04. Promise 只是確保在 Promise 控制的範圍內可以照順序
    在呼叫 Promise 時 本身還是非同步
    故底下會先印出 "after" 而不是 "in then"

    async function test() {
        return Promise.resolve();
    }

    test.then(() => {
        console.log("in then");
    });

    console.log("after");

05. async / await 只是語法糖,骨子裡還是 Promise 的運用

2018年8月28日 星期二

Javascript Array fill function


var result = Array(5).fill(['-', '-']);

console.log('before', result);

result[0][1] = 'modify result[0]';

console.log('after ', result);


如果 fill 傳進去的是 1 個物件
如上例中的 ['-', '-']

最後 result array 裡面的元素
都會是同 1 個物件的 reference

這會造成明明只是要改 1 個 element
卻變成 5 個 element 都一起生效

真是 1 個神奇的 bug

2017年9月6日 星期三

Javascript 正規表示法

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp

純 Javascript 中使用正規表示法

regex 是一個正規表示
str 是一個字串
info 是執行 exec 回傳的 array

因為我們有用 "( )" 圈住數字
故 array[1] 會是 123
而 array[2] 會是 456


程式範例
var regex = /(\d+) (\d+)/;
var str = '123 456';
var info = regex.exec(str);

for (var i = 0; i < info.length; i++) {
    console.log(i, info[i]);
}

執行結果
0 '123 456'
1 '123'
2 '456'

如果字串中有 1 個以上要匹配的地方,我們可以考慮使用 flag 'g'
如果忘記加上 'g',程式便會進入無窮迴圈,因為 regex.lastIndex always = 0
var regex = /(\d+) (\d+)/g;
var str = '123 456; 789 100';

var info;
while ((info = regex.exec(str)) != null) {
    console.log(regex.lastIndex);
    for (var i = 0; i < info.length; i++) {
        console.log(i, info[i]);
    }
}

執行結果
7
0 '123 456'
1 '123'
2 '456'
16
0 '789 100'
1 '789'
2 '100'