Promise对象是CommonJS工作组为异步编程提供的统一接口,是ECMAScript6中提供了对Promise的原生支持,Promise就是在未来发生的事情,使用Promise可以避免回调函数的层层嵌套,还提供了规范更加容易的对异步操作进行控制。提供了reject,resolve,then和catch等方法。
Promise规范https://promisesaplus.com/中对Promise的状态的定义:
Promise 是一个对象。Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败),只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。其状态改变只有两种可能:从pending变为fulfilled和从pending变为rejected。只要这两种情况发生,状态就凝固了,不会再变了。
Promise构造函数接收一个函数作为参数,该函数的两个参数分别是resolve方法和reject方法。如果异步操作成功,则用resolve方法将Promise对象的状态变为"成功"(即从pending变为resolved); 如果异步操作失败,则用reject方法将状态变为"失败"(即从pending变为rejected)。例一:
var getJSON = function(url) {
var promise = new promise(function (resolve, reject) {
var client = new XMLHttpRequest();
client.open('GET', url);
client.onreadystatechange = handler;
client.responseType = 'json';
client.setRequestHeader('Accept', 'application/json');
client.send();
function handler() {
if (this.readyState === this.DONE) {
if (this.status === 200) {
resolve(this.response);
}
else {
reject(this);
}
}
}
});
return promise;
};
getJSON('/posts.json').then(function (json) {
// continue
}, function (error) {
// handle errors
});
例二:
getRequest = function (url) {
var promise = new Promise(function (resolve, reject) {
var request = require('request');
request(url, function (error, respones, body) {
if (error) {
reject(error);
return;
}
if (respones.statusCode == 200) {
resolve(body)
} else {
reject(respones.status);
}
});
});
return promise;
};
getRequest("https://github.com/").then(function (result) {
console.log(result);
}, function (error) {
console.error('error', error);
});
例三:
updateKinds ({commit, state}) {
return new Promise(function (resolve, reject) {
axios.get('/bbg/shop/get_classify', {
params: {
sid: 13729792
}
})
.then(function (response) {
if (response.data.code == 130) {
commit(UPDATE_KINDS, response.data.data)
console.log(response.data.data);
resolve()
}
}).catch(function (error) {
console.log(error);
});
});
返回一个promise,当请求到数据,并且commit之后,我们就额可以resolve()了,这样,就可以在then中执行获取所有内容的方法了。
例四:
var promise = new Promise(function (resolve, reject) {
console.log('begin do something');
if (Math.random() * 10.0 > 5) {
console.log(" run success");
resolve();
} else {
console.log(" run failed");
reject();
}
});
这里定义了一个回调方法function(resolve,reject),如果成功了就调用resolve,失败了就会调用reject。
以下例子来源于网上
let promise = new Promise(function(resolve, reject) {
console.log('Promise execute');
resolve();
});
promise.then(function() {
console.log('after Resolved');
});
console.log('test async!');
// Promise execute
// test async!
// after Resolved
创建Promise对象表示创建了一个立即执行的代码。
new Promise(function(resolve) {
el.onclick = resolve
}).then(function() {
console.log('clicked')
})
// 点击el元素多次
// clicked(只会打印一次clicked,因为不会出现两次成功状态)
承诺状态只会改变一次,状态一旦改变就不会再改变。换句话说,回调函数只会执行一次,且成功与失败回调函数只会执行其中一个。
另一个例子:
var p1 = new Promise(function(re, rj) {
rj()
re()
})
p1.
then(function() {
console.log(1)
}, function() {
console.log(2)
})
// 2(re方法不会执行,因为状态已经变为失败)
const preloadImage = function(path) {
return new Promise(function(resolve, reject) {
var image = new Image();
image.onload = resolve;
image.onerror = reject;
image.src = path;
});
};
const a = upload('images/1.jpeg')
// 数秒后在控制台写下Promise的回调函数
a.then(function() {
console.log('image loaded')
})
// image loaded(load事件早已经触发,但是你并没有错过他)
承诺无论你什么时候提供回调函数,只要状态改变过就会执行回调函数。
按文章开头处的说明,主要需要注意三点:
首先定义两个function:
let func = function() {
return new Promise((resolve, reject) => {
resolve('返回值');
});
};
let cb = function() {
return '新的值';
}
然后执行1:
func().then(function () {
return cb();
}).then(resp => {
console.warn(resp);
console.warn('1 =========<');
});
//新的值
//1 =========<
这里resp的值为上面cb()返回的值。
执行2:
func().then(function () {
cb();
}).then(resp => {
console.warn(resp);
console.warn('2 =========<');
});
//undefined
//2 =========<
then中传入的回调方法没有返回值,所以resp为undefined。
执行3:
func().then(cb()).then(resp => {
console.warn(resp);
console.warn('3 =========<');
});
//返回值
//3 =========<
then中cb()执行后返回的并不是一个函数,在Promise规范中会自动忽略调当前then,所以会把func(resolve方法)中的返回值供下一个then使用,输出了“返回值”
执行4:
func().then(cb).then(resp => {
console.warn(resp);
console.warn('4 =========<');
});
//新的值
//4 =========<
这里把cb当做回调,传入的是cb函数,与执行1的情况相同。
Promise.prototype.catch方法是.then(null, rejection)的别名,用于指定发生错误时的回调函数。
getJSON('/posts.json').then(function(posts) {
// ...
}).catch(function(error) {
// 处理 getJSON 和 前一个回调函数运行时发生的错误
console.log('发生错误!', error);
});
Promise.all方法用于将多个 Promise 实例,包装成一个新的 Promise 实例。
const p = Promise.all([p1, p2, p3]);
上面代码中,Promise.all方法接受一个数组作为参数,p1、p2、p3都是 Promise 实例,如果不是,就会先调用下面讲到的Promise.resolve方法,将参数转为Promise 实例,再进一步处理。(Promise.all方法的参数可以不是数组,但必须具有 Iterator 接口,且返回的每个成员都是 Promise 实例。)p的状态由p1、p2、p3决定,分成两种情况:
Promise.race方法同样是将多个 Promise 实例,包装成一个新的 Promise 实例。
const p = Promise.race([p1, p2, p3]);
上面代码中,只要p1、p2、p3之中有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给p的回调函数。
Promise.race方法的参数与Promise.all方法一样,如果不是 Promise 实例,就会先调用下面讲到的Promise.resolve方法,将参数转为 Promise 实例,再进一步处理。下面是一个例子,如果指定时间内没有获得结果,就将 Promise 的状态变为reject,否则变为resolve。
const p = Promise.race([
fetch('/resource-that-may-take-a-while'),
new Promise(function (resolve, reject) {
setTimeout(() => reject(new Error('request timeout')), 5000)
})
]);
p.then(console.log)
.catch(console.error);
上面代码中,如果 5 秒之内fetch方法无法返回结果,变量p的状态就会变为rejected,从而触发catch方法指定的回调函数。
async function testResult() {
let result = await doubleAfter2seconds(30);
console.log(result);
}
function doubleAfter2seconds(num) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(2 * num)
}, 2000);
} )
}
基本规则: