bluebird-Core API(一)

new Promise

new Promise(function(function resolve, function reject) resolver) -> Promise

建立一個新的Promise,傳入一個函數,這個函數有兩個函數resolve、reject做爲參數。這兩個參數函數能在這個函數被調用。html

Example:java

function ajaxGetAsync(url) {
    return new Promise(function (resolve, reject) {
        var xhr = new XMLHttpRequest;
        xhr.addEventListener("error", reject);
        xhr.addEventListener("load", resolve);
        xhr.open("GET", url);
        xhr.send(null);
    });
}

若是你給resovle函數傳入Promise對象,被建立的Promise將會跟隨傳入Promise的狀態。ajax

To make sure a function that returns a promise is following the implicit but critically important contract of promises, you can start a function with new Promise if you cannot start a chain immediately:c#

function getConnection(urlString) {
    return new Promise(function(resolve) {
        //Without new Promise, this throwing will throw an actual exception
        var params = parse(urlString);
        resolve(getAdapter(params).getConnection());
    });
}

The above ensures getConnection fulfills the contract of a promise-returning function of never throwing a synchronous exception. Also see Promise.try and Promise.methodapi

The resolver is called synchronously (the following is for documentation purposes and not idiomatic code):數組

function getPromiseResolveFn() {
    var res;
    new Promise(function (resolve) {
        res = resolve;
    });
    // res is guaranteed to be set
    return res;
}

 

.then

.then(
    [function(any value) fulfilledHandler],
    [function(any error) rejectedHandler]
) -> Promise

.spread

.spread(
    [function(any values...) fulfilledHandler]
) -> Promise

像調用.then同樣,可是傳遞過來的值必須是一個數組,用於展開上面fulfillment handler的形參。promise

Promise.delay(500).then(function() {
   return [fs.readFileAsync("file1.txt"),
           fs.readFileAsync("file2.txt")] ;
}).spread(function(file1text, file2text) {
    if (file1text === file2text) {
        console.log("files are equal");
    }
    else {
        console.log("files are not equal");
    }
});

若是使用ES6,上面代碼能夠使用.then方法來代替安全

Promise.delay(500).then(function() {
   return [fs.readFileAsync("file1.txt"),
           fs.readFileAsync("file2.txt")] ;
}).all().then(function([file1text, file2text]) {
    if (file1text === file2text) {
        console.log("files are equal");
    }
    else {
        console.log("files are not equal");
    }
});

注意:這裏.spread就至關於隱式調用了.all()app

If you want to coordinate several discrete concurrent promises, use Promise.joinless

.catch

.catch是便於處理Promise chains錯誤的方法,它有兩種變體(使用方式),一種catch-all相似於同步的代碼塊catch(e){,這種方式兼容原生的Promise,一種filtered變體(像其餘非js語言典型特性),讓你只處理特定的錯誤,這種方式更加合理,更加安全。

Promise處理異常

Promise異常處理仿照原生JavaScript異常處理,一個同步函數throw相似於Promise中的rejecting,catch均可以處理,以下面例子:

function getItems(parma) {
    try { 
        var items = getItemsSync();
        if(!items) throw new InvalidItemsError();  
    } catch(e) { 
        // can address the error here, either from getItemsSync returning a falsey value or throwing itself
        throw e; // need to re-throw the error unless I want it to be considered handled. 
    }
    return process(items);
}

一樣的,Promise

function getItems(param) {
    return getItemsAsync().then(items => {
        if(!items) throw new InvalidItemsError(); 
        return items;
    }).catch(e => {
        // can address the error here and recover from it, from getItemsAsync rejects or returns a falsey value
        throw e; // Need to rethrow unless we actually recovered, just like in the synchronous version
    }).then(process);
}
  
Catch-all
.catch(function(any error) handler) -> Promise
.caught(function(any error) handler) -> Promise

這是catch-all異常處理句柄,也能夠簡寫.then(null,hanlder),.then -chain中任何異常出現時候都會在它最近的catch中處理。

爲了兼容ES版本,爲catch提供了別名caught

Filtered Catch
.catch(
    class ErrorClass|function(any error)|Object predicate...,
    function(any error) handler
) -> Promise
.caught(
    class ErrorClass|function(any error)|Object predicate...,
    function(any error) handler
) -> Promise

這種方式是對catch一種擴展,像java和c#中catch用法同樣,代替了手動instanceof or .name === "SomeError"來判斷不一樣異常,

你能夠對catch句柄指定一些合適的錯誤構造函數,這些catch句柄(hanlder)遇到合適的指定錯誤構造函數,catch句柄將會被調用,例如:

somePromise.then(function() {
    return a.b.c.d();
}).catch(TypeError, function(e) {
    //If it is a TypeError, will end up here because
    //it is a type error to reference property of undefined
}).catch(ReferenceError, function(e) {
    //Will end up here if a was never declared at all
}).catch(function(e) {
    //Generic catch-the rest, error wasn't TypeError nor
    //ReferenceError
});

You may also add multiple filters for a catch handler:

你可能對於一個catch句柄加入多個異常:

somePromise.then(function() {
    return a.b.c.d();
}).catch(TypeError, ReferenceError, function(e) {
    //Will end up here on programmer error
}).catch(NetworkError, TimeoutError, function(e) {
    //Will end up here on expected everyday network errors
}).catch(function(e) {
    //Catch any unexpected errors
});

若是你過濾錯誤(指定執行某個錯誤),參數必須被確認是error類型,你須要對.prototype屬性構造 instanceof Error.

以下面的構造函數例子:

function MyCustomError() {}
MyCustomError.prototype = Object.create(Error.prototype);

使用方式

Promise.resolve().then(function() {
    throw new MyCustomError();
}).catch(MyCustomError, function(e) {
    //will end up here now
});

無論怎麼樣若是你想輸出詳細信息和打印堆棧,在Node.js和最新V8引擎支持Error.captureStackTrace

function MyCustomError(message) {
    this.message = message;
    this.name = "MyCustomError";
    Error.captureStackTrace(this, MyCustomError);
}
MyCustomError.prototype = Object.create(Error.prototype);
MyCustomError.prototype.constructor = MyCustomError;

使用CoffeeScript's class:

class MyCustomError extends Error
  constructor: (@message) ->
    @name = "MyCustomError"
    Error.captureStackTrace(this, MyCustomError)

This method also supports predicate-based filters(這方法支持謂語filters). If you pass a predicate function instead of an error constructor(若是是傳入是謂語函數代替錯誤構造器【啥叫謂語函數,按照我對上下文理解:就是返回true或者false的函數】), the predicate will receive the error as an argument. The return result of the predicate will be used determine whether the error handler should be called.

Predicates should allow for very fine grained control over caught errors: pattern matching, error-type sets with set operations and many other techniques can be implemented on top of them.

Example of using a predicate-based filter:

var Promise = require("bluebird");
var request = Promise.promisify(require("request"));

function ClientError(e) {
    return e.code >= 400 && e.code < 500;
}

request("http://www.google.com").then(function(contents) {
    console.log(contents);
}).catch(ClientError, function(e) {
   //A client error like 400 Bad Request happened
});

謂語函數只有檢查屬性時候方面速記,你能經過傳入對象來代替謂語函數,依靠錯誤對象匹配上檢查對象的屬性:

fs.readFileAsync(...)
    .then(...)
    .catch({code: 'ENOENT'}, function(e) {
        console.log("file not found: " + e.path);
    });

The object predicate passed to .catch in the above code ({code: 'ENOENT'}) is shorthand for a predicate function function predicate(e) { return isObject(e) && e.code == 'ENOENT' }, I.E. loose equality is used.

By not returning a rejected value or throw ing from a catch, you "recover from failure" and continue the chain:

若是你對於一個catch不返回一個rejected value 或者 throw,你「重置錯誤」就能夠繼續走下這個chain

Promise.reject(Error('fail!'))
  .catch(function(e) {
    // fallback with "recover from failure"
    return Promise.resolve('success!'); // promise or value
  })
  .then(function(result) {
    console.log(result); // will print "success!"
  });

This is exactly like the synchronous code:

var result;
try {
  throw Error('fail');
} catch(e) {
  result = 'success!';
}
console.log(result);
相關文章
相關標籤/搜索