new Promise
new Promise(function(function resolve, function reject) resolver) -> Promise
创建一个新的Promise,传入一个函数,这个函数有两个函数resolve、reject作为参数。这两个参数函数能在这个函数被调用。
Example:
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的状态。
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:
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
and Promise.try
Promise.method
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.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()
If you want to coordinate several discrete concurrent promises, use Promise.join
.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);