1、promise概念
* Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。
* 简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。
* 从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理。
2、promise特点
有且只有这两种,而且一个peomise对象只能改变一次,无论变为成功还是失败,都会有一个结果数据,成功的结果数据一般为value,失败的结果数据一般被称为reason
它只有两种状态(PromiseState)可以转化,即
- **操作成功:**pending -> fulfilled/resolved
- **操作失败:**pending -> rejected
实例对象的值:PromiseResult。该对象保存的结果为异步任务成功和失败的结果
* 成功的结果 resolve
* 失败的结果 rejected
promise有三个状态:
1、pending[待定]初始状态
2、fulfilled[实现]操作成功
3、rejected[被否决]操作失败
resolve作用是,将Promise对象的状态从“未完成”变为“成功”(即从 pending 变为 resolved),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;
reject作用是,将Promise对象的状态从“未完成”变为“失败”(即从 pending 变为 rejected),在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。
3、promise实现原理
ES6 规定,`Promise` 对象是一个构造函数,用来生成 `Promise` 实例。通过在函数内部 return 一个 `Promise` 对象的实例,这样就可以使用 `Promise` 的属性和方法进行下一步操作了。
```javascript
Promise 构造函数接受一个函数作为参数,该函数的两个参数分别是 resolve 和 reject。它们是两个函数,由 JavaScript 引擎提供,不用自己部署
promise的方法:`then()`方法就是把原来的回调写法分离出来,在异步操作执行完后,用链式调用的方式执行回调函数.
而 `Promise`的优势就在于这个链式调用。我们可以在 then 方法中继续写 `Promise` 对象并返回,然后继续调用 `then` 来进行回调操作。
问题一:函数内部的异步函数
怎样才能取得到函数内部的data
```
```javascript
1、promise构造函数的参数是个函数
2、该函数的参数有两个:resolve,reject
resolve:异步操作成功,要调用的函数。是then函数的第一个参数
reject表示操作失败,要调用的时候是then函数的第二个参数
```4、promise的api方法
4.1、**.then(callback)**
Promise对象含有then方法,then()调用后返回一个Promise对象,意味着实例化后的Promise对象可以进行链式调用,而且这个then()方法可以接收两个函数,一个是处理成功后的函数,一个是处理错误结果的函数。
var promise1 = new Promise(function(resolve, reject) {
// 2秒后置为接收状态
setTimeout(function() {
resolve('success');
}, 2000);
});
promise1.then(function(data) {
console.log(data); success
}, function(err) {
console.log(err); // 不执行
}).then(function(data) {
// 上一步的then()方法没有返回值
console.log('链式调用:' + data); // 链式调用:undefined
}).then(function(data) {
// ....
});
4.2、**.catch(callback)**
catch()方法和then()方法一样,都会返回一个新的Promise对象,它主要用于捕获异步操作时出现的异常。因此,我们通常省略then()方法的第二个参数,把错误处理控制权转交给其后面的catch()函数
```javascript
const p = new Promise((resolve, reject) => {
// 修改p的状态
reject('失败')
})
console.log(p);
p.catch(data => {
console.log(data);
})
4.3、**.all()**
Promise.all()
Promise包含n个promise的数组,说明:返回一个新的promise,只有promise都成功才成功,只要有一个失败了,就都失败
```javascript
const p1 = new Promise((resolve, reject) => {
resolve('ok')
})
const p2 = new Promise((resolve, reject) => {
resolve('okhaha')
})
const p3 = new Promise((resolve, reject) => {
resolve('kobab')
})
const result = Promise.all([p1,p2,p3]);
console.log(result);
4.4 .race()
Promise包含n个promise的数组,说明:返回一个promise,第一个完成的promise的结果状态就是最终的结果状态
```javascript
const p1 = new Promise((resolve, reject) => {
resolve('ok')
})
const p2 = new Promise((resolve, reject) => {
resolve('jj')
})
const p3 = new Promise((resolve, reject) => {
resolve('ll')
})
const result = Promise.race([p1,p2,p3]);
console.log(result);
```
5、promise封装ajax
```javascript
```
async 和await
```javascript
async 函数 await 后跟着一个promise对象
async function getData(){
let hotpot = await getHotpot(); //拿到resolve传递出来的数据
console.log(hotpot);
let tea = await getTea();
consloe.log(tea);
}
getData();
一.ajax的同源策略
Ajax请求限制:
Ajax 只能向自己的服务器发送请求。比如现在有一个A网站、有一个B网站,A网站中的 HTML 文件只能向A网站服务器中发送 Ajax 请求,B网站中的 HTML 文件只能向 B 网站中发送 Ajax 请求,但是 A 网站是不能向 B 网站发送 Ajax请求的,同理,B 网站也不能向 A 网站发送 Ajax请求。
**什么叫同源策略**
同源策略是浏览器的一个安全功能,不同源的客户端脚本在没有明确授权的情况下,不能读写对方资源
**同源策略的目的**
同源策略是为了保证用户信息的安全,防止恶意的网站窃取数据。最初的同源政策是指 A 网站在客户端设置的 Cookie,B网站是不能访问的。
随着互联网的发展,同源政策也越来越严格,在不同源的情况下,其中有一项规定就是无法向非同源地址发送Ajax 请求,如果请求,浏览器就会报错。
二.jsonp跨域
##### 使用JSONP解决同源限制问题
jsonp的原理:页面上的很多标签比如src,href,都不会受到同源策略的影响
有一些标签天生就有跨域能力,比如:img,link,iframe,script
jsonp就是利用`<script>`的src来实现跨域获取数据的,只支持get请求
jsonp 由两部分组成:回调函数和数据,回调函数是当响应到来时应该在页面中调用的函数。回调函数的名字一般是在请求中指定的。而数据就是传入回调函数中的 JSON 数据
jsonp 是 json with padding 的缩写,它不属于 Ajax 请求,但它可以模拟 Ajax 请求。
1. 将不同源的服务器端请求地址写在 script 标签的 src 属性中
```javascript
<script src="www.example.com"></script>
```
2. 服务器端响应数据必须是一个函数的调用,真正要发送给客户端的数据需要作为函数调用的参数。
```javascript
const data = 'fn({name: "张三", age: "20"})';
echo data;
```
3. 在客户端全局作用域
```javascript
function fn(data){}
```
4. 在fn函数内部对服务器端返回的数据进行处理
```javascript
function fn(data){
console.log(data);
}
```
整体实现思路:
1. 客户端需要将函数名称传递到服务器端
2. 将script请求的发送变成动态的请求。
```javascript
<script>
function fn(data){
console.log(data);
}
// 接收后端响应的数据
</script>
<script src="data.php?callback=fn"></script>
```
后端:
```javascript
<?php
$cb = $_GET['callback']; //接收前端的参数:callback fn
$data = "i am back";
echo $cb.'("'.$data.'")'; // fn('123')
?>
echo '字符串'
```
高级版实现:
```javascript
<script>
function fn1(data) {
console.log('客户端的fn函数被调用了');
console.log(data);
}
function add(){
// 创建srcipt标签
var oSrc = document.createElement('script');
oSrc.src = 'http://192.168.52.1/workspace/demo/code3/data.php?callback=fn1';
document.body.appendChild(oSrc);
// 监听script标签什么时间加载完成,
oSrc.onload = function(){
oSrc.remove();
}
}
</script>
``
高级封装
```javascript
1. 客户端需要将函数名称传递到服务器端
2. 将script请求的发送变成动态请求
3. 封装jsonp函数,方便请求发送
```
```javascript
<script>
function add() {
jsonp({
url: 'http://192.168.52.1/workspace/data.php',
data:{},
success:function(data){
console.log(data);
}
})
}
function jsonp(options) {
var script = document.createElement('script');
var fn = 'myscript'+Math.random().toString().replace('.','');
window[fn]=options.success;
script.src = options.url+'?callback='+fn+getParams(options.data);
document.body.appendChild(script);
// 监听script标签什么时间加载完成,
script.onload = function () {
script.remove();
}
}
function getParams(obj){
var arr = [];
for(var k in obj){
arr.push(k+'='+obj[k]);
}
return arr;
}
</script>
三.服务器端跨域
CORS:全称为 Cross-origin resource sharing,即跨域资源共享,它允许浏览器向跨域服务器发送 Ajax 请求,克服了 Ajax 只能同源使用的限制。
前端请求地址:
```javascript
http://192.168.52.1/workspace/day05/cros.php
```
后端设置:
```javascript
Access-Control-Allow-Origin: 'http://localhost:3000'
Access-Control-Allow-Origin: '*'
```
header(‘Access-Control-Allow-Origin: *’);
如果想设置只允许某个网站通过的话可以这样设置
header(’Access-Control-Allow-Origin: http://test.com‘); // 允许test.com发起的跨域请求,其他的都不通过
六. 请求天气预报
接口文档:
```javascript
请求方式:GET
请求地址: 'https://wis.qq.com/weather/common',
必要参数:
province: "陕西省",
city: "西安市",
source:'pc',
weather_type:'forecast_1h'
搜索框自动搜索
```javascript
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
</head>
<body>
<input type="text">
<script src="./jsonp.js"></script>
<script>
var oTxt = document.querySelector('input')
oTxt.oninput = function () {
jsonp({
type:'GET',
url: 'https://suggest.taobao.com/sug',
data: {
q: this.value,
},
success: function (data) {
console.log(data);
}
})
}
</script>
</body>
</html>