es6中的promise
Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。
有了Promise对象,就可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。此外,Promise对象提供统一的接口,使得控制异步操作更加容易。
Promise也有一些缺点:
- 首先,无法取消Promise,一旦新建它就会立即执行,无法中途取消。
- 如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。
- 当处于pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。
promise的特点
- 对象的状态不受外界影响。Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。
- 一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise的对象状态改变,要么是成功,要么就是失败,只要发生这两种情况,状态就会凝固,称为resolvd(已定型)。改变发生后,再添加回调函数,也是会得到这个结果。
用法
创造Promise实例
Promise对象是一个构造函数,用来生成Promise实例。
const promise = new Promise(function(resolve, reject) {
if (/* 异步操作成功 */){
resolve(value);
} else {
reject(error);
}
});
resolve函数的作用是,将Promise对象的状态从“未完成”变为“成功”(即从 pending 变为 resolved),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;
reject函数的作用是,将Promise对象的状态从“未完成”变为“失败”(即从 pending 变为 rejected),在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。
then方法
接着用then方法指定resolved状态和rejected状态的回调函数:
promise.then(
function (value) {
// success
},
function (error) {
// failure
}
);
第一个函数是状态对象变为rejected的调用,第二个是resolved的调用,第二个函数是可选的。
then方法返回的是一个新的Promise实例(注意,不是原来那个Promise实例)。因此可以采用链式写法,即then方法后面再调用另一个then方法。
promise.then(function(value) {
}.then(function (comments) {
console.log("resolved: ", comments);
}, function (err){
console.log("rejected: ", err);
});
catch方法
用于指定发生错误时的回调函数。
promise
.then(
function (value) {
// success
},
function (error) {
// failure
}
)
.catch(function (error) {
// 处理发生的错误
console.log('发生错误!', error);
});
如果异步操作抛出错误,状态就会变为rejected,就会调用catch()方法指定的回调函数,处理这个错误。另外,then()方法指定的回调函数,如果运行中抛出错误,也会被catch()方法捕获。
跟传统的try/catch代码块不同的是,如果没有使用catch()方法指定错误处理的回调函数,Promise 对象抛出的错误不会传递到外层代码,即不会有任何反应。
finally方法
用于指定不管 Promise 对象最后状态如何,都会执行的操作。
promise
.then(
function (value) {
// success
},
function (error) {
// failure
}
)
.catch(function (error) {
// 处理发生的错误
console.log('发生错误!', error);
})
.finally(function () {
alert('finish');
});
finally方法的回调函数不接受任何参数,意味着无法知道最终的状态是怎样的。
Jquery、Ajax、Promise示例
之前学了Jquery和ajax,就顺手在网上随便找了个api测试下:
const apiUrl = 'https://suggest.taobao.com/sug?code=utf-8&q=电脑&callback=cb';
$('#bt').click(apiUrl, function (event) {
const promise = new Promise(function (resolve, reject) {
$.ajax({
url: event.data,
type: 'get',
dataType: 'jsonp',
headers: {
Accept: 'application/json; charset=utf-8',
},
success: function (data) {
resolve(data);
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
reject(XMLHttpRequest, textStatus, errorThrown);
},
});
});
promise
.then(
function (data) {
console.log(data);
let x = data.result;
for (let i = 0; i < data.result.length; i++) {
console.log(x[i][0]);
}
},
function (XMLHttpRequest, textStatus, errorThrown) {
alert(XMLHttpRequest);
alert(textStatus);
alert(errorThrown);
}
)
.catch(function (error) {
console.log(error);
})
.finally(function () {
alert('finish');
});
});
结果:
遇到的问题
其实在Promise基础的学习上没有什么太大的问题,但是在ajax请求的时候遇上了一个跨域的问题,就是:
Access to XMLHttpRequest at ‘这里是api’ from origin ‘null’ has been blocked by CORS policy: No ‘Access-Control-Allow-Origin’ header is present on the requested resource.
这是什么啊…… 简单的了解了下,先说说跨域的概念吧
每个网站只能读取同一来源的数据,这里的同一来源指的是主机名(域名)、协议(http/https)和端口号的组合。在没明确授权的情况下,不能读写对方的资源,它是浏览器最核心也最基本的安全功能;只要有一个不一样就跨域。
而Ajax的XMLHttpRequest受到了同源限制,只能访问同源下的数据,所以就报这个错。 所以怎么还没说怎么解决嗷???
在搜到的文章里面大部分都是后端配合设置一个请求权限,但是我这是野生的api。。。我还腆着脸去要求别人做这做那哦?
直到我找到个方法,jsonp
jsonp:
- 通过script标签引入某些数据,是同步模式的,用script标签做跨域的时候,不建议将数据提前加载,需要按需加载;
- 当需要数据的时候创建一个script标签,将需要的数据放在src中,通过onload去监听是否请求过来,请求完毕就调用传回来的数据(异步加载);
- jsonp不能用post请求,只能是get请求;
所以为啥这个类型就可以跨域了???
带src属性script、img、iframe、link等标签是不需要遵守同源策略的,但是通过src加载的资源,浏览器限制了javascript的权限, 能读不能写
综上所述:把dataType类型从json改成jsonp就可以了。