JS中的Promise:

MDN上面对promise的描述:Promise 对象用于表示一个异步操作的最终状态(完成或失败),以及其返回的值。

可以直接对字面上理解:Promise:承诺,一诺千金,只要你有承诺就得执行,不管时间过了多久,执行完就行,而且还是异步的,比如你是一个言出必行的大丈夫,你说总有一天完会把大黄蜂(科迈罗)买回家,奋斗了5年攒够了钱,然后下单,异步就是你承诺了要买大黄蜂,但你还是可以做其他的事,因为生活总得继续。

console.log('下个目标,5年买科迈罗!');
new Promise((resolve, reject) => {
console.log('正在奋斗中。。。。');
//你可以执行的代码
//经过了5年的奋斗,我们用延迟函数代替代码执行的时间,3秒
setTimeout(() => {
console.log('奋斗了5年,并攒够了钱!');
resolve('下单');
},3000)
}).then(value => {
console.log(`${value},带着女神出去浪`);
})
console.log('一边享受生活一边奋斗。。。。');

运行结果:

下个目标,5年买科迈罗!
正在奋斗中。。。。
一边享受生活一边奋斗。。。。
奋斗了5年,并攒够了钱!
下单,带着女神出去浪

这是最简单的Promise了,接下来我们正式介绍一下Promise:MDN描述:Promise 对象是一个代理对象(代理一个值),被代理的值在Promise对象创建时可能是未知的。它允许你为异步操作的成功和失败分别绑定相应的处理方法(handlers)。 这让异步方法可以像同步方法那样返回值,但并不是立即返回最终执行结果,而是一个能代表未来出现的结果的promise对象。

简单来说Promise里面可以执行一些获取数据库数据的代码,因为获取时间比较长,因为JS是单线程的,不能因为获取数据让其他事件不能加载。

一个 Promise有以下几种状态:

  • pending: 初始状态,既不是成功,也不是失败状态。
  • fulfilled: 意味着操作成功完成。
  • rejected: 意味着操作失败。

返回看上面那个例子,一开始有两个参数resolve => 成功, reject => 失败.还有个重点:Promise状态发生改变,就会触发.then()里的响应函数,处理后续步骤.

console.log('start');
new Promise((resolve, reject) => {
console.log('first promise');
resolve('succeed');
setTimeout(() => {
console.log('最后才执行到我!');
},2000)
}).then(value => {
console.log(`${value},first then`);
})

运行结果:

start
first promise
succeed,first then
最后才执行到我!

上面那个例子,执行到resolve(),当前的promise的状态改变了,就开始执行下面的then,不会等待settimeout执行完。

结合下面的图可以理解下:

当然promise还可以当作一个变量来对待,比如下面的例子,不一定要紧接着()后面.then();

console.log('start');

let promise = new Promise((resolve, reject) => {
setTimeout(() => {
console.log('the promise fulfilled');
resolve('hello,world');
},1000);
}); //上面的promise完成后,过3秒再执行then,还是可以存在的,可以作为一个变量。
setTimeout(() => {
promise.then(value => {
console.log(value);
})
},3000)

接下来来说说.then(),经过上面的理解,可以看出.then()相当于一个promise,它也返回一个新的Promise实例,所以它可以链式调用,接受两个参数,也就是Promise中的两个状态:fulfilled,rejected,当前面的Promise状态改变时,.then()根据其最终状态,选择特定的状态响应函数执行。

'use strict';

console.log('that\'s begin');
let myPromise = new Promise((resolve, reject) => {
console.log('first promise');
//resolve是传递参数给下一个then
resolve('first succeed');
}).then( value => {
console.log('value');
return new Promise((resolve, reject) => {
setTimeout(() => {
reject('thie is error');
},2000)
});
//当上面出错时调用下面的catch
}).catch((reason) => {
console.log(reason);
})

再看个返回失败的例子,返回成功时用resolve,后面就用.then()来处理后续步骤,返回失败时用rejected,后面就用.catch()来处理后续步骤。

console.log('that\'s begin');
let myPromise = new Promise((resolve, reject) => {
console.log('first promise');
//resolve是传递参数给下一个then
resolve('first succeed');
}).then( value => {
console.log('first then succeed');
return new Promise((resolve, reject) => {
setTimeout(() => {
reject('thie is error');
},2000)
});
//当上面出错时调用下面的catch
}).then( value => {
console.log(`成功执行到最后:${value}`);
})
.catch( reason => {
console.log(`最终以失败告终:${reason}`);
})

运行结果:

that's begin
first promise
succeed
最终以失败告终:thie is error

下面讲一个Promise的all函数:Promise.all(iterable) 方法返回一个 Promise 实例,此实例在 iterable 参数内所有的 promise 都“完成(resolved)”或参数中不包含 promise 时回调完成(resolve);如果参数中  promise 有一个失败(rejected),此实例回调失败(rejecte),失败原因的是第一个失败 promise 的结果,MDN讲的很清晰,直接看例子:

console.log('start all promise');
let promise1 = Promise.reject('我是第一个reject');
let promise2 = 42;
let promise3 = new Promise((resolve, reject) => {
setTimeout(() => {
reject('我是第二个reject');
},1000);
});
Promise.all([promise1, promise2, promise3]).then( value =>{
console.log(value);
}).catch(reason => {
console.log(`失败原因的是第一个失败 promise 的结果:${reason}`);
})

运行结果:

start all promise
失败原因的是第一个失败 promise 的结果:我是第一个reject

如果都是resolve的话才算成功,如果前面的promise没有返回resolve或者没有返回reject那么下面的then()就不会执行。

JS中的跨域

请求跨域有好多种,

一、跨域资源共享:

也就是设置服务端的header,可以指定哪些域名可以请求,也是最简单的跨域方式(自我感觉),并且可以支持post等等。

//指定允许其他域名访问
'Access-Control-Allow-Origin:*'//或指定域
//响应类型
'Access-Control-Allow-Methods:GET,POST'
//响应头设置
'Access-Control-Allow-Headers:x-requested-with,content-type'

二、jsonp

由于浏览器的同源策略,所以ajax不能直接跨域请求数据,我们把浏览器的安全策略组关掉(也就是关掉同源策略)就可以啦,当然这是开个玩笑。想了解可以访问这个网站:https://www.cnblogs.com/zhongxia/p/5416024.html

上面说的是ajax会被同源策略拦截下来,但是script中的src并不会被拦截,我们可以利用这个特性实现跨域:

<script>
//下面就输出你在服务端请求的数据
function dosomething(data){
console.log(data);
}
</script>
//src 就是你想要请求的地址,cb是请求时带的参数,这是必须要加的,因为上面的函数名也是这个
<script src="http://localhost:8080/ChickensSys/backDate?cb=dosomething"></script>

服务端要做相应的配合,这边是用javaweb来调试:在doGet函数里面添加这些代码:

        response.setContentType("text/html");
request.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
String cbString = request.getParameter("cb");
PrintWriter out = response.getWriter();
out.println(cbString + "("this is jsonP ")");
out.flush();
out.close();

仔细看:out.println(cbString + "("this is jsonP ")");

我们把参数结果带入进去,可以发现输出的是cb("this is jsonP");相当于是调用这个函数,没错,结果就是这样。

你会看到页面的控制台打印了this isjsonP。

结论:我们用src(不会被同源策略拦截)请求别的域名的数据,返回的结果放在已定义好的函数参数里面并且执行这个函数,然后你要对数据做哪些操作就可以在函数里面随便操作。

三、window.name + iframe跨域获取数据

这个的原理和jsonP差不多吧,也是利用src,不过这次是利用iframe(可以理解html中一个内嵌页面,也可以包含一个html文件)的src和window.name的特性来跨域, window.name属性的神奇之处在于name 值在不同的页面(甚至不同域名)加载后依旧存在(如果没修改则值不会变化),并且可以支持非常长的 name 值(2MB)。也就是你第一次设置后,不管你的iframe重定向到哪个页面,window.name都不会变。

     <script type="text/javascript">
let iframe = document.createElement('iframe');
//src你请求的地址,此时会报错,说你跨域了
iframe.src = 'http://localhost:8080/ChickensSys/backDate';
document.body.appendChild(iframe);
iframe.onload = function() {
//在本地新建空白的proxy.html因为上面报错了,这边赶紧重定向到本地的proxy.html
iframe.src = 'proxy.html';
//contentWindow属性是指指定的frame或者iframe所在的window对象。
console.log(iframe.contentWindow.name)
};
</script>

服务端需要相应的配合:

out.println("<script>window.name = \"this is CORS</script>");

预期结果跟我们想的一样,一开始报错,我们重定向到本地后就没报错,输出结果也是没错的,因为服务端输出的是一个脚本,window.name=" ";还记得上面讲过window.name 值在不同的页面(甚至不同域名)加载后依旧存在(如果没修改则值不会变化)。但是为什么会一直调用onload函数呢,因为在onload函数中又被重定向所以又一次调用,跟递归差不多意思。既然可以拿到数据,那我们下面来改进下,让它不报错,并只拿到一次数据。

    <script>
let iframe = document.createElement('iframe');
iframe.style.display = 'none';
var state = 0;
iframe.onload = function() {
//重定向完,可以取window.name的数据了,这边可以对数据进行处理
if(state === 1) {
var data = iframe.contentWindow.name;
console.log(data);
//移除这个节点,其实上面display:none已经对dom无影响了,这个加了保险
document.body.removeChild(iframe);
//当下面的iframe.src执行到时,也就是第一次onload,迅速重定向到本地
} else if(state === 0) {
state = 1;
iframe.src = 'proxy.html';
}
};
iframe.src = 'http://localhost:8080/ChickensSys/backDate';
document.body.appendChild(iframe);
</script>

运行结果:

只有一次请求。

上面只是讲下原理,我们可以对上面做个封装,封装成一个函数,方便以后用:

    <script>
//url是请求的地址,handle是处理数据的函数
function getDataWithIframe(url, handle){
let iframe = document.createElement('iframe');
iframe.style.display = 'none';
var state = 0;
iframe.onload = function() {
//重定向完,可以取window.name的数据了,这边可以对数据进行处理
if(state === 1) {
handle(iframe.contentWindow.name);
//移除这个节点,其实上面display:none已经对dom无影响了,这个加了保险
document.body.removeChild(iframe);
//当下面的iframe.src执行到时,也就是第一次onload,迅速重定向到本地
} else if(state === 0) {
state = 1;
iframe.src = 'proxy.html';
}
};
iframe.src = url;
document.body.appendChild(iframe);
}
let url = 'http://localhost:8080/ChickensSys/backDate';
getDataWithIframe(url, function(data){
console.log('这是请求来的数据:' + data);
})
</script>

总结:看了好多跨域,大部分都是通过src来跨域的,但好像通过src的都只能是get请求,比如刚说的jsonP和iframe+window.name的方式都是通过get来请求数据,而且都是需要要后端进行相应的配合,比如jsonP需要加个cb()来执行函数,iframe需要<script>window.name=" "</script>来执行赋值语句,第一种设置后端的header的方式倒是可以支持post请求,真是又简单又好用。。。

深入浅出JS:Two的更多相关文章

  1. 深入浅出js事件

    深入浅出js事件 一.事件流 事件冒泡和事件捕获分别由微软和网景公司提出,这两个概念是为了解决页面中事件流(事件发生顺序)的问题. <div id="outer"> & ...

  2. 深入浅出JS的封装与继承

    JS虽然是一个面向对象的语言,但是不是典型的面向对象语言.Java/C++的面向对象是object - class的关系,而JS是object - object的关系,中间通过原型prototype连 ...

  3. 深入浅出js实现继承的7种方式

    给大家介绍7中js继承的方法 有些人认为JavaScript并不是真正的面向对象语言,在经典的面向对象语言中,您可能倾向于定义类对象,然后您可以简单地定义哪些类继承哪些类(参考C++ inherita ...

  4. 深入浅出js中的this(一)

    Q:this是什么? A:this是Javascript语言的一个关键字,它代表函数运行时,自动生成的一个内部对象,在每个 function 中自动根据作用域(scope) 确定, 指向的是此次调用者 ...

  5. 深入浅出js中的this

    Q:this是什么? A:this是Javascript语言的一个关键字,它代表函数运行时,自动生成的一个内部对象,在每个 function 中自动根据作用域(scope) 确定, 指向的是此次调用者 ...

  6. 《JS高程》事件学习笔记

    事件:文档或浏览器窗口中发生的一些特定的交互瞬间,也即用户或浏览器自身执行的某种动作. -------------------------------------------------------- ...

  7. JS:事件循环机制、调用栈以及任务队列

    点击查看原文 写在前面 js里的事件循环机制十分有趣.从很多面试题也可以看出来,考察简单的setTimeout也就是考察这个机制的. 在之前,我只是简单地认为由于函数执行很快,setTimeout执行 ...

  8. web前端知识总结

    前言: 一直想着整理一下关于前端的知识体系和资料,工作忙了些,挤挤总会有的,资料很多,就看你能不能耐下心坚持去学了,要多学多敲多想,祝你进步~ 学习之前首先要大概了解什么是HTML ,CSS , JS ...

  9. 介绍Ext JS 4.2的新特性的《深入浅出Ext JS》上市

    以用户为中心的时代,应用的界面外观变得越来越重要.然而,很多程序员都缺乏美术功底,要开发出界面美观的应用实属不易.Ext JS的出现,为广大程序员解决了这一难题.它有丰富多彩的界面和强大的功能,是开发 ...

随机推荐

  1. 2019杭电多校第四场hdu6623 Minimal Power of Prime

    Minimal Power of Prime 题目传送门 解题思路 先打\(N^\frac{1}{5}\)内的素数表,对于每一个n,先分解\(N^\frac{1}{5}\)范围内的素数,分解完后n变为 ...

  2. upc组队赛14 Evolution Game【dp】

    Evolution Game 题目描述 In the fantasy world of ICPC there are magical beasts. As they grow, these beast ...

  3. Locally weighted regression algorithm

    之前所讨论的梯度下降算法,其算法模型是“线性回归模型”,我们可以理解为变量与因变量之间的关系是线性的.而现实情况是,使用线性模型去描述所有数据,很容易出现欠拟合(underfitting)的情况:同样 ...

  4. 关于shell脚本中的别名问题

    在shell脚本中,shell中的alias别名是不会起作用的,在脚本中的命令都是按着环境变量PATH直接找到命令文件而执行的,所以就不用担心脚本里的命令会与shell中的个性别名冲突啦~

  5. vue PC端页面引入vue-quill-editor富文本插件

    项目需要:在添加新类别的弹框中,要在输入框中输入多条描述信息,不同的描述信息要换行输入,输入后点击确定传给后端,接口返回成功后点击查看刚添加的新类别时,描述框中展现多条换行的描述信息也要跟填写时一样( ...

  6. rem适配布局(rem+less+媒体查询 和 rem+flexible.js)

    1. rem 基础 rem 是一个相对单位,类似于 em ,em 是父元素字体大小. em 是相对于父元素  的字体大小来说的 rem 是相对于 html 元素 字体大小来说的 rem 优点 就是可以 ...

  7. vue中key的作用

    1.v-if中用key管理可复用的元素  Vue 会尽可能高效地渲染元素,通常会复用已有元素而不是从头开始渲染.这么做,除了使 Vue 变得非常快之外,还有一些有用的好处.例如,如果你允许用户在不同的 ...

  8. 6、Python 中 利用 openpyxl 读 写 excel 操作

    __author__ = 'Administrator' from openpyxl import load_workbook # Excel_Util 类 class Excel_util: #初始 ...

  9. JavaScript常见设计模式梳理

    单例模式 单例模式,顾名思义就是保证每个类都只有一个实例对象. 其实现思路很简单,先判断实例是否存在,如果不存在则创建新的实例返回,如果存在则直接返回该实例. 策略模式 策略模式可以理解为:封装多个可 ...

  10. leetcode-12双周赛-1246-删除回文子数组

    题目描述: 方法:区间dp O(N^3) class Solution: def minimumMoves(self, A: List[int]) -> int: N = len(A) dp = ...