有时候,你会发现满世界都是某个字眼。

Promise,就是这个家伙。简直阴魂不散,走到哪儿都能看到它。fetchkoa中都有TA的身影,而我却对TA一无所知。
搜索TA的文章介绍,第一页中最早的一篇文章已经是2011年了。那是个我还不会HelloWorld的年代啊!

用法

Promise 对象用于延迟(deferred) 计算和异步(asynchronous ) 计算。一个Promise对象代表着一个还未完成,但预期将来会完成的操作。

看概念很迷糊,直接看实例理解吧。

function $http(url){
var core = {
ajax : function (method, url, args) {
var promise = new Promise( function (resolve, reject) {
var client = new XMLHttpRequest();
var uri = url;
if (args && (method === 'POST' || method === 'PUT')) {
uri += '?';
var argcount = 0;
for (var key in args) {
if (args.hasOwnProperty(key)) {
if (argcount++) {
uri += '&';
}
uri += encodeURIComponent(key) + '=' + encodeURIComponent(args[key]);
}
}
}
client.open(method, uri);
client.send();
client.onload = function () {
if (this.status >= 200 && this.status < 300) {
resolve(this.response);
} else {
reject(this.statusText);
}
};
client.onerror = function () {
reject(this.statusText);
};
});
return promise;
}
};
return {
get : function(args) {
return core.ajax('GET', url, args);
},
post : function(args) {
return core.ajax('POST', url, args);
},
put : function(args) {
return core.ajax('PUT', url, args);
},
delete : function(args) {
return core.ajax('DELETE', url, args);
}
};
};
$http('http://url/api').get({
id: 111
}).then(function(data){
// success
}, function(data){
// error
});

以上是一个基于 Promise 的 ajax 实现,调用形式跟 vue-resource 如出一辙(果然又是大神们嚼烂的玩意儿)。

Promise 的构造函数可以带有1个参数,它是带有resolvereject两个参数的函数对象,如以上core.ajax函数中创建的 Promise 对象。
其中 resolve 用于处理执行成功的场景,reject 用于处理执行失败的场景。
在成功与失败的处理阶段 hook 到一个 Promise 对象中,最后通过then方法来真正的处理返回结果。

  • Promise.prototype.then(onFulfilled[, onRejected])
  • Promise.prototype.catch(onRejected)

并不是所有的失败场景都需要在then方法中处理,在其后继续追加catch方法也是可以的。

$http('http://url/api').get({
id: 111
}).then(function(data){
// success
}).catch(function(data){
// error
});

由于thencatch仍然返回一个 Promise 对象,所以可以出现多个thencatch来处理不同的业务场景。

$http('http://url/api').get({
id: 111
}).then(function(data){
return handleA(data);
}).then(function(data){
// 此处 data 为 handleA 方法处理后的数据
return handleB(data);
});

为何要用

咋一看 Promise 就是一个包装好的代理对象。不过它的出现究竟是为了解决什么问题呢?

在 Promise 出现之前,如果你的逻辑中出现了异步操作,而又需要在异步操作外获取异步操作内的结果,不外乎是要使用回调了。

function getList(callback) {
$.get(yourApi, function(data){
callback(data);
});
}

使用 Promise 呢?

function getList() {
return new Promise( function (resolve, reject) {
$.get(yourApi, function(data){
resolve(dat