} else {
reject(new Error(this.statusText));
}
}
});
return promise;
}
getJSON(‘info.json’).then(
json => id.innerHTML = “
” + json + “”,
err => id.innerHTML = err
);
如果 resolve 的参数是一个promise:
var p1 = new Promise(function(resolve, reject){
//…
});
var p2 = new Promise(function(resolve, reject){
//…
resolve(p1);
});
上面代码中 p1 的状态传给了 p2,也就是p1运行完成(状态为 resolve 或 reject)后 p2 的回调函数会立刻开始执行:
var p1 = new Promise(function(resolve, reject){
setTimeout(() => reject(new Error(‘failed’)), 3000);
});
var p2 = new Promise(function(resolve, reject){
setTimeout(() => resolve(p1), 1000);
});
p2.then(result => console.log(result));
p2.catch(error => console.log(error));
p1 建立,进入 setTimeout 异步计时器。之后 p2 建立,进入 setTimeout 异步计时器。1s 后 p2 准备执行 resolve, 但是 resolve 的参数是 p1, 此时 p1 还是 Pending 状态,所以 p2 开始等待。又过了 2s, p1 的 reject 执行,变为 rejected 状态,随即 p2 也跟着变成 rejected 状态。
Promise 对象方法
- then() 方法
then(resolve(value){},reject(value){})
方法接受2个函数参数,resolve 在 Promise 状态变为 resolved 时调用,reject 在 Promise 状态变为 rejected 时调用。其中 reject 参数是可选的。和构造函数不同的是,then 方法的 reject 和 resolve 都使用 promise 传出的值作为其唯一的参数。
then()
方法返回一个新的 Promise 实例,注意,不是之前那个。因此可以用链式调用,不断添加”回调”函数。 then 的返回值成了下一个 then 中回调函数的参数:
var p = new Promise(function(resolve, reject){
resolve(“from new Promise”);
}).then(function (value){
console.log(value); //from new Promise 其次输出这个
return “from the first ‘then’”;
}).then(function(value){
console.log(value); //from the first ‘then’ 最后输出这个
return “from the second ‘then’”;
});
console.log§; //Promise{…} 先输出这个
注意,如果 promise 的状态是 resolved 则执行 then参数中的第一个回调函数;如果 promise 的状态是 rejected 则执行 then参数中的第二个回调函数。这个状态是不断传递下来的,这一点和之前的例子类似。
- catch() 方法:
catch(reject) 方法是 then(null, reject)
的别名,在发生错误的时候执行其参数函数:
new Promise(function(resolve, reject){
resolve(“resolved”);
}).then(function(val){
console.log(val); //resolved
throw new Error(“man-made Error”);
}).catch(function(err){
console.log(err.message); //man-made Error
});
错误会从最初的请求沿着回调函数,一直被传递下来。这一点和传统的错误冒泡类似,无论哪里有错误都可以被捕获到:
new Promise(function(resolve, reject){
reject(new Error(“original Error”));
}).then(function(val){
console.log(val); //不执行
throw new Error(“man-made Error”);
}).catch(function(err){
console.log(err.message); //original Error
});
当然也可以在半路截住错误:
new Promise(function(resolve, reject){
reject(new Error(“original Error”));
}).then(function(val){
console.log(val); //不执行
throw new Error(“man-made Error”);
}, function(err){
console.log(Uncaught Error: ${err.message}
); //Uncaught Error: original Error
}).catch(function(err){
console.log(err.message); //不执行
});
这里需要注意以下几点:
-
reject 和 throw 一样可以抛出错误。
-
在 Promise 状态变为 resolved 或 rejected 之后抛出的错误会被忽略。
-
建议总是使用 catch() 方法,而不要在 then() 方法中定义 reject 函数。
-
如果一个 promise 既没有 catch方法,也没有可以捕获到错误的 then 方法,那么这个错误就消失了。它不会到 promise 外面来。
-
try…catch… 只能捕获同步代码的错误,不能捕获异步代码的错误(这个是 ES5 就有的)。
-
catch() 方法可以继续抛出错误,就像 try…catch 中的 catch 一样可以抛出错误。
这里需要说明的是第4条:错误不会到 Promise 外面是 ES6 规范的说法。具体理解(浏览器环境):控制台依旧会报错,但是不影响 promise 语句之后续代码执行。此外,promise 语句内的异步语句(如事件,定时器等等)抛出的错误,不属于 promise 内部,发生错误会传播出去:
var p = new Promise(function(resolve, reject){
resolve(“ok”);
setTimeout(function(){throw new Error(“setTimeout error”)},0);
});
p.then(function(val){console.log(val);}); //ok
//Uncaught Error: setTimeout error
其次,就以上前两个注意事项举一例说明:
new Promise(function(resolve, reject){
resolve(“resolved”);
throw “original Error”; //被忽略
}).then(function(val){
console.log(val); //resolved
throw (new Error(“man-made Error”));
}).catch(function(err){
console.log(err.message); //man-made Error
});
catch 方法的返回值还是一个新的 promise 对象,可以继续调用 then 等其他方法:
new Promise(function(resolve, reject){
reject(new Error(“reject”));
}).catch(function(err){
console.log(“1st catch”); //被跳过
return “continue”;
}).then(function(val){
console.log(val); //continue
});
如果 catch之前没有错误,该 catch 会被跳过。这意味着,catch 不能捕获在其后面的语句中出现的错误:
new Promise(function(resolve, reject){
resolve(“resolved”);
}).catch(function(err){
console.log(“1st catch”); //被跳过
}).then(function(val){
console.log(val); //resolved
throw (new Error());
}).catch(function(err){
console.log(“2nd catch”); //2nd catch
});
- finally() 方法
finally() 接受一个回调函数(无参数)为参数,和 try…catch…finally 中的 finally 类似,不论 promise 是什么状态,该回调函数都一定会运行。可以用它关闭文件,或者关闭服务器等:
server.listen(0).then(function(){
//do sth.
}).finally(server.stop);
finally() 内部实现如下:
Promise.prototype.finally = function(callback){
return this.then(
value => {Promise.resolve(callback()).then(() => value)},
error => {Promise.resolve(callback()).then(() => {throw error})}
);
};
- done() 方法
done() 方法用在 promise 处理语句的末端,用来处理可能未捕获的错误,并抛向全局。如果其带有参数,可以等效为 done() 之前多了一个 then():
p.done(fun1, fun2);
//相当于
p.then(fun1,fun2).done();
done() 内部实现如下:
Promise.prototype.done = function(onResolve, onRejected){
this.then(onResolve, onRejected).catch(function(err){
setTimeout(() => {throw err}, 0);
});
};
Promise 静态方法
- Promise.all()
将多个 promise 对象合并成一个新的 promise 实例。其接受一个装仅有 promise 对象的可遍历结构为参数,如果不是 promise 对象,系统会调用 Promise.resolve()
进行类型转换。
promise.all() 方法得到的新的 promise 对象状态由构成它的所有 promise 对象决定,具体分为2种情况:
-
当所有构成它的 promise 对象的状态都变成 resolved,这个新的对象状态才变为 resolved。此时构成它所有的 Promise 的返回值构成一个数组作为新的 promise 对象的回调函数参数;
-
当所有构成它的 promise 对象的状态有一个变成 rejected,这个新的对象状态就变为 rejected。此时第一个被 reject 的 Promise 的返回值作为新的 promise 对象的回调函数参数;
//伪代码, 由于没有正确的 url
var getJSON = function(url){
var promise = new Promise(function(resolve, reject){
var client = new XMLHttpRequest();
client.open(“GET”, url);
client.onreadystatechange = handler;
client.response = “json”;
client.setRequestHeader(“Accept”, “application/json”);
client.send();
function handler(){
if(client.readyState !== 4) return;
if(this.status === 200){
resolve(client.response);
} else {
reject(new Error(this.statusText));
}
}
});
return promise;
}
var pros = [‘url1’, ‘url2’, ‘url3’].map(url => getJSON(url));
Promise.all(pros).then(function(){
console.log(“all successful”);
}, function(){
console.log(“one rejected”); //one rejected, 由于没有正确的 url
});
- Promise.race()
将多个 promise 对象合并成一个新的 promise 实例。其接受一个装仅有 promise 对象的可遍历结构为参数,如果不是 promise 对象,系统会调用 Promise.resolve()
进行类型转换。
和 promise.all() 不同的是 Promise.race() 方法得到的新的 promise 对象状态由构成它的 promise 对象中最先改变状态的那一个决定。
//伪代码, 由于没有正确的 url
var getJSON = function(url){
var promise = new Promise(function(resolve, reject){
var client = new XMLHttpRequest();
client.open(“GET”, url);
client.onreadystatechange = handler;
client.response = “json”;
client.setRequestHeader(“Accept”, “application/json”);
client.send();
function handler(){
if(client.readyState !== 4) return;
if(this.status === 200){
resolve(client.response);
} else {
reject(new Error(this.statusText));
}
}
});
return promise;
}
//如果5s不能获得数据就报错
var p = Promise.race([
getJSON(“url”),
最后
推荐一些系统学习的途径和方法。
每个Web开发人员必备,很权威很齐全的Web开发文档。作为学习辞典使用,可以查询到每个概念、方法、属性的详细解释,注意使用英文关键字搜索。里面的一些 HTML,CSS,HTTP 技术教程也相当不错。
HTML 和 CSS: