ES6中的Promise
在执行一些异步操作(典型的有JavaScript中的ajax/NodeJs中读取文件等等)的时候,我们不知道该操作什么时候完成,所以就需要在不同的时候写上回调,等到有返回的时候,再执行下一步操作,下面就用jQuery中的一个ajax来做示例:
$.ajax({
"url": "xxx",
"type": "GET",
"dataType": ""JSON,
"success": function(res){},
"error": function(ex){
// do some thing
}
});
最基础的一个ajax示例,当我们有多个ajax嵌套请求的时候,就中了所谓的"回调地狱",类似于下面的写法:
$.ajax({
// some configs
"success": function(res){
$.ajax({
// ...
"success": function(res){
$.ajax({
// ...
"success":function(res){
.
.
.
}
});
}
});
}
});
一层套着一层,代码可读性很差,且不容易后期的维护
这时候就需要一个比前者好的解决方案来解决该问题,ES6中的Promise一定程度上解决了该问题:
我们可以利用Promise对ajax进行一层封装
function _ajax(url, method, args) {
let promise = new Promise((resolve, reject) => {
let client = new XMLHttpRequest();
let uri = url;
if (args && (method == "POST" || method == "PUT")) {
let argcount = 0;
uri += "?";
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;
}
let core = {
"GET": function(args) {
return _ajax(url, "GET", args);
},
"POST": function(args) {
return _ajax(url, "POST", args);
},
"PUT": function(args) {
return _ajax(url, "PUT", args);
},
"DELETE": function(args) {
return _ajax(url, "DELETE", args);
}
};
上面这段代码是JavaScript MDN上的代码(可能稍微有点改动),它对ajax进行了一层封装,经过这层封装,我们可以像下面这样写一些异步代码:
$http("xxx")
.GET()
.then((data) => {
// do something
$http("xxx2")
.GET()
.then((data) => {
// do something
$http("xxx3")
.GET({"key","value"})
.then((data) => {
// do something...
})
},(ex) => {});
})
.catch((ex) => {});
虽然还有嵌套,但是代码看起来已经舒服了很多。
Promise是一个异步编程的抽象,它是一个返回值或抛出exception的代理对象,一般promise对象都有一个then方法,这个then方法是我们如何获得返回值(成功实现承诺的结果值,称为fulfillment)或抛出exception(拒绝承诺的理由,称为rejection),then是用两个可选的回调作为参数,我们可以称为onFulfilled和OnRejected,也可以把OnRejected写在catch里面
所以一个Promise一共有下面几个状态
- pending待承诺 - promise初始状态
- fulfilled实现承诺 - 一个承诺成功实现状态
- rejected拒绝承诺 - 一个承诺失败的状态
再来个NodeJs中读取文件的例子:
function readFile(path) {
var fs = require("fs");
var prromise = new Promise((resolve, reject) => {
fs.readdir(path, (ex, files) => {
if (ex) {
return reject(ex);
}
return resolve(files);
});
});
return prromise;
}
readFile(config.avatarPath + "1").then((files) => {
// do some thing
console.log(files);
}).catch((ex) => {
// do something...
console.log(ex);
});
如果不用Promise和一些ES6的特性,上面的代码应该看起来是下面的这样子:
var fs = require("fs");
fs.readdir(path, function (ex, files) {
if (ex) {
// do something
return console.log();
}
// do some thing
console.log(files);
});
代码量可能更少,但是陷入"回调地狱"的可能就更大了,在ES7中,又新增了async/await特性来针对异步操作的,后面介绍😄