1. Promise.resolve
:把一个value
值包装成promise
返回
let p=Promise.resolve(2)
equals to let p=new Promise((resolve)=>{resolve(2)});
example:
var loadCache;
function loadUrl(url){
var cache=loadCache.cache || ( loadCache.cache=new Map() );
if(cache.has(url)) return Promise.resolve( cache.get(url) );
return fetch(url)
.then( response=>response.json() )
.then( text=>{
cache.set(url,text);
return text;
}
}
Promise.resolve
保证了这个函数的返回结果在两种情况下都会是 promise
对象,保证了接口的统一性。
2. Promise.all
: 返回promise对象,输入参数为数组,数组中的元素为promise
let p=Promise.all([...promise...]);
simple example:
Promise.all([
new Promise(resolve => setTimeout(resolve(1),1000) ),
new Promise(resolve => setTimeout(resolve(2),2000) ),
])
.then(console.log);
//output: [1,2]
我们来看看Promise.all
的一些应用实例:
-
example 1: 在这里例子中,
Promise.all
会等到request
数组中的3个promise
都resolved
之后,然后自己resolve
,去执行.then()
中的部分。
let urls = [
'https://api.github.com/users/iliakan',
'https://api.github.com/users/remy',
'https://api.github.com/users/jeresig'
];
// 将每个 url 映射到 fetch 的 promise 中
let requests = urls.map(url => fetch(url));
// Promise.all 等待所有作业都被 resolve
Promise.all(requests)
.then(responses => responses.forEach(
response => alert(`${response.url}: ${response.status}`)
));
-
example 2: 在example 1的基础上,我们进一步利用
promise
的链式调用。
let names = ['iliakan', 'remy', 'jeresig'];
let requests = names.map(name => fetch(`https://api.github.com/users/${name}`));
Promise.all(requests)
.then(responses => {
// 所有响应都就绪时,我们可以显示 HTTP 状态码
for(let response of responses) {
alert(`${response.url}: ${response.status}`); // 每个 url 都显示 200
}
return responses;
})
// 映射 response 数组到 response.json() 中以读取它们的内容
.then(responses => Promise.all(responses.map(r => r.json())))
// 所有 JSON 结果都被解析:“users” 是它们的数组
.then(users => users.forEach(user => alert(user.name)));
Promise.all
其他的一些要点:
- 如果传给输入参数数组的不是
promise
,是一个值,那么Promise.resolve
会将其包装成一个resolved promise
; - 如果其中的一个
promise
是reject
状态,Promise.all
会等待其他promise
的执行结果,但是最后的返回结果是rejected promise
3. Promise.allSettled
:对Promise.all
的信息补充
简单来说,这个函数是把数组中的每个resolved value
包装成一个object
, 根据数组中每个返回的promise
的状态将其包装成{status: 'fulfilled', value: resolved value}
or {status: 'rejected', reason: error}
4. Promise.race
:只关心第一个完成的promise
, 之后的promise都不会被执行。
5. Promise.reject
:与Promise.resolve
相似
6. Promisification
Promisification
非常有意思,一般回调函数的形式大多为func(para1,para2,...,callback)
,promisify
的过程为:
function(para1,para2,...,paraM){
return new Promise( (resolve,reject)=>{
func1(para1,para2,...,paraM, (error, result)=>{
if(error) reject( new Error('whoops'));
else resolve(result);
}
}
);
}
//我们把这一过程继续包装:
function promisify(f){
return function(...args){
return new Promise((resolve,reject)=>{
function callback(error,result){
if(error) reject(new Error('whoops');
else resolve(result);
}
args.push(callback);
f.apply(this,...args);
});
}
}
//如果callback的参数不止两个
function promisify(f,manyArgs=false){
return function(...args){
return new Promise((resolve,reject)=>{
function callback(error,...result){
if(error) reject(new Error('whoops');
else resolve(manyArgs ? result : result[0]);
}
args.push(callback);
f.apply(this,...args);
});
}
}
我们在promise
中定义回调函数,在其中我们根据error
参数的有无来决定promise
的状态,然后将回调函数push
到函数的arguments
中,执行我们想要包装的函数。
这样改写之后,原先放在callback
中的操作也会放入.then()
函数中,符合promise
的正常代码逻辑。
7. async, await
首先我们要记住一条,就是await
只能在async
函数里面使用,如果在顶层代码中使用会报错。
-
async
保证函数的返回值会被包装成一个promise
-
await
保证只有当前的promise
ready之后才会执行后续的代码,是更优雅地改写promise.then().then()
链式调用的语法。
我们来看一个例子:
async function showAvatar(){
let response = await fetch('/profiles/user.json');
let user = await response.json();
let githubResponse = await fetch(`https://www.github.com/user?${user.name}`);
let githubUser = await githubResponse.json();
let img = document.createElement('img');
img.src=githubUser.avatar_url;
document.body.append(img);
await new Promise(resolve=>setTimeout(resolve,3000)); //(*)
img.remove();
return githubUser;
}
(*)处的await
保证了图片会在页面中保留3s
await handling error:
(async function(){
let result=await Promise.reject('whoops');
})().catch(console.log);
//'whoops'
//equals to:
(async function(){
try{
let result=await Promise.reject('whoops');
}catch(e){
console.log(e);
}
})();