unhurried

コンピュータ関連ネタがほとんど、ときどき趣味も…

How to cope with Callback Hell #1 Promise

We often fall into what is called "Callback Hell" when we write some asynchronous processes with Node.js, which is a problem the hierarchy of the code becomes too deep.

There are many countermeasures and it looks a little messy, so I will sort out them in several posts. This time, I will introduce the way of returning Promise objects which hold the running state in an asynchronous process instead of making a callback an argument.

// An example of a function returning Promise.
var promiseFunction = function(message, timeout) {
    // Pass a function which has resolve and reject as arguments
    // when creating a Promise object.
    // * resolve: a function returning an object when the process succeeds
    // * reject: a function returning an error object when the process fails
    return new Promise(function(resolve, reject){
        setTimeout(function() {
            console.log(message);
            resolve(message);
            // Call reject function when an error occurs.
            // reject(error);
        }, timeout);
    });
};

// The usage of a Promise instance
var promise = promiseFunction('promise', 100);
// then: write post-processing
promise.then(function(result){
    console.log("result: " + JSON.stringify(result));
// catch: write error processing
}).catch(function(error){
    console.log("error: " + JSON.stringify(error));
});

Result

$ node promise.js
promise
result: "promise"

Reference

Callback地獄対策 (1) Promise

NodeJSで非同期処理を書いていくと必ずはまるのが、Callbackで階層が深くなりすぎるいわゆるCallback地獄です。対策を調べてみたところ色々ありすぎて混乱してきてしまったので、何回かに分けて整理してみようと思います。

今回は、非同期処理を行う関数でCallbackを引数にとる代わりに、実行状態を保持するPromiseオブジェクトを返却する方法をまとめてみました。

// Promiseを返却する関数の例
var promiseFunction = function(message, timeout) {
    // Promiseオブジェクト生成時の引数に
    // resolve、rejectを引数に持つFunctionを渡す
    // * resolve: 処理成功時の返却オブジェクトを渡す関数
    // * reject: 処理失敗時のエラーオブジェクトを渡す関数
    return new Promise(function(resolve, reject){
        setTimeout(function() {
            console.log(message);
            resolve(message);
            // エラー発生時はreject関数を呼び出す
            // reject(error);
        }, timeout);
    });
};

// Promiseインスタンスの使い方
var promise = promiseFunction('promise', 100);
// then関数:後処理を記述する
promise.then(function(result){
    console.log("result: " + JSON.stringify(result));
// catch関数:エラー処理を記述する
}).catch(function(error){
    console.log("error: " + JSON.stringify(error));
});

実行結果

$ node promise.js
promise
result: "promise"

参考: http://qiita.com/koki_cheese/items/c559da338a3d307c9d88

Forever Stampでアメリカから国際郵便を送る

アメリカから国際郵便(USPS Frist-Class Mail Int'l)を送るときはGlobal Forever Stampを1枚貼れば良いのですが、普段国内郵便しか使わない人にとっては、Global Forever Stampが手元にないことが多いと思います。調べてみると、国内郵便用のForever Stampでも少し損はするものの国際郵便も送れるそうです。

→ Foever Stampを3枚貼れば国際郵便を送ることができます。

Google Cloud Print APIを使った印刷手順

最近はどのプリンターもインターネットに繫がっているのが当たり前になって来ています。Webサービスを作るときにバックグラウンドでプリンターに印刷ジョブを投げれたらいいなというケースがいくつかあったので、その手段の一つとしてGoogle Cloud Print APIを調べてみました。

Google Cloud Print APIを使ってWebページを印刷する手順

(0) Google API ConsoleでクライアントIDとクライアントシークレットを取得する

(1) 認可画面を出力し、ユーザーから認可をもらう

https://accounts.google.com/o/oauth2/v2/auth?
redirect_uri={登録したリダイレクトURI}&
response_type=code&
client_id={発行されたクライアントID}&
scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fcloudprint&
access_type=offline

(2) リダイレクトURIにて認可コードを受信し、アクセストークンを取得する

  • リダイレクトURIのcodeパラメータに認可コードが付与されてリダイレクトされて来ます。
  • URIから取得した認可コードをToken Endpointに送信し、アクセストークンを取得します。
リクエスト

POST https://www.googleapis.com/oauth2/v4/token
Content-Type: application/x-www-form-urlencoded

code={認可コード}&
client_id={発行されたクライアントID}&
client_secret={発行されたクライアントシークレット}&
redirect_uri={登録したリダイレクトURI}&
grant_type=authorization_code

レスポンス

{
  "access_token": {アクセストークン},
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": {リフレッシュトークン}
}

(3) プリンター検索APIを呼び出し、印刷したいプリンタのプリンタIDを取得する

リクエスト

GET https://www.google.com/cloudprint/search
Authorization: OAuth {アクセストークン}

レスポンス

{
    "printers": [
    {
        "id": {プリンタID},
        "displayName": {プリンタの表示名},
        ...
    }]
        ...
}

(4) プリンタジョブ送信APIを呼び出し、印刷を実行する

  • 例)URLを指定してそのWebページを印刷するリクエスト
POST https://www.google.com/cloudprint/submit
Content-Type: application/x-www-form-urlencoded

printerId={プリンタID}&
title={印刷タイトル}&
contentType=url&
content={印刷するURL}&
ticket={チケットオブジェクト}
{"version":"1.0","print":{"vendor_ticket_item":[],"color":{"type":"STANDARD_MONOCHROME"},"copies":{"copies":1}}}

参考

成田・サンフランシスコ間航空機の荷物制限

成田からアメリカへのフライトの際にできる限り多くの物を持っていこうと、成田・サンフランシスコ間を就航している航空会社の荷物制限を調べていました。どなたかの参考になるかもしれないので、載せておきます。

  • アメリカン航空
    • 手荷物の制限:23kg/個、158㎝/個
    • 無料範囲:2個
    • サイズ超過:最大320cm/個(230cm以上は要問合せ)
    • 重量超過:最大45kg/個(32kg以上は要問合せ)
    • 数量超過:特に規定なし
  • ユナイテッド航空
    • 手荷物の制限:23kg/個、158㎝/個
    • 無料範囲:1or2個
    • サイズ超過:最大292cm/個
    • 重量超過:最大43kg/個
    • 数量超過:一部路線では3個まで
  • 全日空
    • 手荷物の制限:23kg/個、158㎝/個
    • 無料範囲:2個
    • サイズ超過:最大320cm/個
    • 重量超過:最大45kg/個
    • 数量超過:特に規定なし

H2O Wireless Voice Mail設定

北米に来てから日本で購入・アクティベートしたH2O Wirelessを活用していますが、しばらくVoice Mailの設定ができないでいました。というのも、私の場合はKDDI Mobileのマニュアルの方法では設定ができなかったのです。

色々と調べてみた結果、以下の手順で設定できることがわかりました。

  • マニュアル中の「5. 留守番電話(ボイスメール)の設定 (1) 留守番電話に接続」の手順を以下の通り変更する。
    • 変更前:「1」の長押し、または「1」をダイヤルする
    • 変更後:自分の電話番号にダイヤルする

その他パスコードのリセットなど、Voice Mail機能の操作手順はH2O Wireless FAQの「Q. How do I access my H2O Wireless Voice Mail?」が参考になります。

日本国内で購入できるアメリカ用SIM

日本国内で購入できる、アメリカ国内通信・通話SIMを調べました。(現地でも調達できるのですが、入国・帰国時の契約の手間を少なくするため)
私の場合は、日本でのアクティベーションができること、日本固定電話通話無料が決めてでH2O Wirelessを契約しました。