for loop in JavaScript

有 index 的 for loop

for (var i = 0; i < 10; i++) {
   console.log(i);
}

for in 用在 object

不能用在 array

var obj = {a:1, b:2, c:3};

for (var prop in obj) {
  console.log("obj." + prop + " = " + obj[prop]);
}

ref:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...in

for of 用在 array(或 iterator 物件)

ES6 才有的語法

let iterable = [10, 20, 30];

for (const value of iterable) {
  console.log(value);
}

不然也可以用 Array.forEach()

[2, 5, , 9].forEach(function (element, index, array) {
  console.log('a[' + index + '] = ' + element);
});

ref:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...of

ES6 Promise 筆記

new Promise() 接受一個 function 做為初始化參數
這個 function 又接受兩個參數 resolvereject
它們都是 function
resolve() 的作用是把 Promise object 的狀態從 pending 改成 resolved / fulfilled(成功)
reject() 則是把狀態從 pending 改成 rejected(失敗)

Promise object 產生之後
可以用 Promise object 的 then() 來指定 resolved 狀態的 callback function
然後 catch() 來指定 rejected 狀態的 callback function

每個 then()catch() 都會 return 一個新的 Promise objecct
如果你在 then() 裡 return 的不是 Promise object
它會隱式地用 Promise.resolve() 幫你轉換

const yourPromiseFunc = function (params) {
  return new Promise((resolve, reject) => {
    doYourAsyncShit(params, (err, data) => {
      if (err) {
        reject(err);
      } else {
        resolve(data);
      }
    });
  });
};

yourPromiseFunc('some parameter')
.then((data) => {
  console.log('success', data);
})
.catch((err) => {
  console.log('fail', data);
});

嚴格來說你只能在 then() 裡做三件事:

  • return 另外一個 Promise object
  • return 一個 synchronous value(字串、數字或其他 object)
  • throw 一個 Error()

如果你沒有顯式地 return 的話,JavaScript 會自動幫你 return undefined;

ref:
http://www.html5rocks.com/zh/tutorials/es6/promises/
http://es6.ruanyifeng.com/#docs/promise#基本用法

使用 reject() 而不是 throw

在 Promise 裡
如果可以用 reject(new Error('your error message')) 就用
不要用 throw new Error('your error message');

基本上就是用 reject() 來表示我們有意識地拋出的錯誤

ref:
http://liubin.org/promises-book/#not-throw-use-reject

把任意 object 轉換成 Promise object

Promise.resolve(xxx); 就是把 xxx 包裝成 Promise object
然後 resolve() 它
如果 xxx 已經是 Promise object 了,則會 clone 一個新的

Promise.resolve(42);

# equals to

new Promise((resolve) => {
  resolve(42);
});

因為所有 Promise 操作都一定是 async 的(這是規格裡規定的)
所以就算是 Promise.resolve(42); 的 42 也不會馬上被執行到

var promise = new Promise(function (resolve) {
    console.log("inner promise"); // 執行順序 1
    resolve(42);
});

promise.then(function(value) {
    console.log(value); // 執行順序 3
});

console.log("outer promise"); // 執行順序 2

ref:
http://liubin.org/promises-book/#chapter2-how-to-write-promise

Promise chains

一律使用 then().catch() 的方式分別指定 resolved 和 rejected 的 callback functions
通常會在 promise chains 的最後放一個 catch()

因為每個 then() 執行完都會 return 一個新的 Promise object(注意!是新的 Promise object,不是你最一開始 new 出來的那個)
所以你可以一直用很多個 then() 串起來
你也可以在 then() 裡 return 某個值作為下一個 then() 的參數

get('story.json')
.then(function(response) {
  return JSON.parse(response);
})
.then(function(data) {
  console.log(data);
});

ref:
http://liubin.org/promises-book/#then-return-new-promise

// 會照順序由上往下執行(除了 .catch() 之外)
Promise.resolve()
  .then(functionA)
  .then(functionB)
  .then(functionC)
  .catch(errorHandler)
  .then(finalFunction);

errorHandler 只能 catch 到 functionA、functionB 和 functionC 中拋出的錯誤

你可以在 then() 裡 return 某個值
他會被包裝成 Promise object(透過 Promise.resolve(某個值))然後傳給下一個 then()

如果你想在 functionC 裡同時使用 funtionA 和 functionB 的結果
你可以這麼寫

firstThingAsync()
  .then(function(result1) {
    return Promise.all([result1, secondThingAsync(result1)]);
  })
  .then(function(results) {
    // do something with results array: results[0], results[1]
  })
  .catch((err) => {
    doErrorHandling();
  });

Anti-patterns

// 這種寫法會造成你的 badAsyncCall() 得不到 newVar 的返回值
function badAsyncCall() {
    var promise = Promise.resolve();
    promise.then(function() {
        return newVar;
    });

    return promise;
}

// 應該要寫成
function badAsyncCall() {
    var promise = Promise.resolve();
    return promise.then(function() {
        return newVar;
    });
}

ref:
https://pouchdb.com/2015/05/18/we-have-a-problem-with-promises.html
http://www.datchley.name/promise-patterns-anti-patterns/

等到所有 promises 都執行完才執行某個動作

你可以用 Promise.all()

Promise.all([promise1, promise2, promise3])
.then((results) => {
  // 這裡會在 promise1, promise2, promise3 的狀態都是 fulfilled 時執行
  // results 的順序跟 .all() 的順序一定會是一致的
  // results[0] 就是 promise1 的回傳值,results[1] 則是 promise2,以此類推
  // 你也可以寫成 .then(([data1, data2, data3]) => {}),不過 Node.js v4.3 還不支援這個語法就是了
})
.catch((err) => {
  // 這裡會在任一個 promise 變成 rejected 時執行
});

ref:
http://www.datchley.name/es6-promises/
https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise/all
http://liubin.org/promises-book/#ch2-promise-all