前言
每一次的学习都能感受到新的东西,很开心
初步总结
-
promise是一个对象,从他可以获取异步操作的消息
-
promise有两个特点
- 对象的状态不受外界影响 有三个状态 pending fullfilled rejected 只有异步操作的结果可以决定当前是哪个状态,任何其他操作都无法改变这个状态
- 一旦状态发生改变就不会再次改变 状态的改变只有从pending -> fullfilled pending -> rejected
-
它解决了一些回调存在的问题,可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。
-
存在着一些缺点
-
如果不设置回调函数,外部无法捕捉到内部出现的错误,一般在Promise链的最后添加一个catch函数。
为什么在最后加呢?
因为对于一个没有错误处理函数的Promise链,任何错误都会在链中被传播下去,直到注册了错误处理函数
-
**无法取消 promise ** 一旦新建它就会立即执行,无法取消
-
无法得知pending状态 当处于pending状态时,我们无法得知究竟是进行到了哪一步,是刚刚开始还是即将完成。
-
文章目录
API
Promise.prototype.catch()
用于指定发生错误时的回调函数
抛出错误的写法有三种
//写法一
var promise = new Promise((resolve, reject) => {
throw new Error('test')
})
promise.catch(function (error) {
console.log(error)
})
//写法二
var promise = new Promise((resolve, reject) => {
try {
throw new Error('test')
} catch (e) {
reject(e)
}
})
promise.catch(function (error) {
console.log(error)
})
//写法三
var promise = new Promise((resolve, reject) => {
reject(new Error('test'))
})
promise.catch(function (error) {
console.log(error)
})
- 如果promise的状态已经变成了Resolved,再抛出错误是不会被捕捉的
var promise = new Promise((resolve, reject) => {
resolve('ok')
throw new Error('test')
})
promise.then((value) => {
console.log(value)
}).catch((error) => {
console.log(error)
})
虽然promise在resolve后面抛出了错误,但是由于promise的状态一旦被改变,就会永久保持该状态,不会再改变了,所以错误不会被捕捉,等于没有抛出
- promise对象的错误具有冒泡性质,会一直向后传递,直到被捕获为止。
//伪代码
getJson('post.json').then(function (post) {
return getJson(post.commentURL)
}).then(function (comments) {
//some code
}).catch(function (error) {
//处理错误
})
- 如果没有使用catch方法指定错误处理的回调函数,Promise对象抛出的错误不会传递到外层代码,即不会有任何反应
var someAsyncThing = function () {
return new Promise(function (resolve, reject) {
// x没有声明,会报错
resolve(x + 2)
})
}
someAsyncThing().then(function () {
console.log('everything is ok')//Uncaught (in promise) ReferenceError: x is not defined
})
someAsyncThing函数产生的Promise对象会报错。但是由于没有指定catch方法,所以方法不会被捕获,也不会传递给外部代码
Promise.prototype.then()
为Promise实例添加状态改变时的回调函数。 函数形式是fn(value){} value是上一个任务的返回结果。
then中的函数一定要返回一个结果或者一个promise对象才可以让之后的then接收
Promise.race()
var p = Promise.race([p1, p2, p3])
promise.race()情况下,只有有一个实例p率先改变状态,p的状态就跟着改变, 率先改变的Promise实例的返回值就就传递给p的回调函数
如果Promise.race()的参数并不是Promise实例,就会先将其参数转化会Promise对象,再做下一步处理
Promise.all()
用于将多个Promise实例包装成一个新的Promise实例
var p = Promise.race([p1, p2, p3])
p的状态有两种情况
- 当p1,p2,p3的状态都由pending -> fufilled ,p的状态才会变成fullfilled。此时,p1,p2,p3的返回值组成一个数组,传递给p的回调函数
- 当p1,p2,p3中有一个被Rejected,p的状态就会变成Rejected,此时第一个被Rejected的实例的返回值就会传递给p的回调函数
Promise.resolve()★★
根据传入的对象决定返回的是什么
- 传入的是个promise实例,原封不动地返回这个实例
function fn (resolve) {
setTimeout(function () {
resolve(123)
}, 3000)
}
let p0 = new Promise(fn)
let p1 = Promise.resolve(p0)
console.log(p0 === p1) // true
Promise.resolve()传入的参数是promise实例时,Promise.resolve()将不做任何修改,原封不动地返回这个实例。所以p0 === p1
- 参数是一个thenable对象
let thenable = {
then: function (resolve, reject) {
resolve(42)
}
}
let p2 = Promise.resolve(thenable)
p2.then(function (value) {
// 当pending -> fullfilled时
console.log(value)
})
当Promise.resolve()传入的参数thenable对象(thenable对象指的是具有then方法的对象),会将这个对象转化为promise对象,然后立即执行thenable方法
- 参数不是具有then方法的对象或者根本不是对象
let p3 = Promise.resolve('hello')
p3.then(function(s){
console.log(s)
})
如上,参数是一个原始值,Promise.resolve()返回一个新的promise对象 (状态为resolved)
- 不带有任何参数时
let p4 = Promise.resolve()
当Promise.resolve()不传入任何参数时,会返回一个状态为resolved的promise对象
题目(1)
function a () {
setTimeout(() => {
console.log("1")
}, 1000);
}
function b () {
setTimeout(() => {
console.log("2")
}, 2000);
}
设计一个promise让先执行b函数,再执行a函数
function a () {
setTimeout(() => {
console.log("1")
}, 1000);
}
function b () {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log("2")
resolve()
}, 2000);
})
}
Promise.resolve().then(function () {
return b()
}).then(function () {
a()
})
上面那个写的一点都不好,于是重新学了一下promise,不断反思,不断进步
function a (resolve, reject) {
setTimeout(() => {
resolve(console.log("1"))
}, 1000);
}
function b (resolve, reject) {
setTimeout(() => {
resolve(console.log("2"))
}, 2000);
}
new Promise(b).then((value) => {
return new Promise(a)
})
这样的话其实就是一个很漂亮的方式了, 不足的是我这样子做,要同时更改a,b函数。不知道有没有什么方法可以在不更改a,b函数的情况下,实现呢?
题目(2)
题目一是同学问我的,当时一瞬间的感觉就是,对promise不熟悉 + 其实具体的思路啊什么的都不是很了解,痛定思痛!! 于是通过一个dalao的文章,逐步实现了一下这个方法~~
参考
实现 通知保姆完成以下事情
- 去超市购买饭和菜
- 用超市买来的菜做饭
- 将饭送到媳妇在的公司,媳妇收到后给我发了个么么哒
- 保姆给我打电话,我给保姆奖励
- 定义买饭,做饭,送饭,给保姆奖励函数
function buyVegetable(resolve, reject) {
setTimeout(() => {
resolve(['西红柿', '鸡蛋', '酱油'])
}, 3000);
}
// 定义做饭函数
function doRice (resolve, reject) {
setTimeout(() => {
resolve({
'主食': '米饭',
'菜': '西红柿炒蛋'
})
}, 3000);
}
// 定义送饭到老婆单位
function sendRice (resolve, reject) {
setTimeout(() => {
// 对送完饭的结果做下一步处理
resolve("老婆的么么哒")
}, 3000);
}
// 给保姆奖钱
function callme() {
console.log("给保姆发奖金")
}
- 对保姆发布命令,让他一步一步实现
new Promise(buyVegetable)
.then((value) => {
return new Promise(doRice)
}).then((value) => {
return new Promise(sendRice)
}).then((value) => {
return new Promise(callme)
})
题目(3)
题目:红灯三秒亮一次,绿灯一秒亮一次,黄灯2秒亮一次;如何让三个灯不断交替重复亮灯?(用 Promse 实现)
// html
<div id = "box"></div>
// css
#box{
width: 50px;
height: 50px;
border-radius: 50%;
background: black;
}
var box = document.getElementById("box");
// 定义三个亮灯函数
function red () {
box.style.backgroundColor = 'red'
}
function yellow () {
box.style.backgroundColor = 'yellow'
}
function green () {
box.style.backgroundColor = 'green'
}
var light = function(timer, callback) {
return new Promise((resolve, reject) => {
setTimeout(() => {
callback()
resolve()
}, timer);
})
}
var step = function() {
Promise.resolve().then(function () {
return light(3000, red)
}).then(function () {
return light(2000, yellow)
}).then(function () {
return light(1000, green)
})
}
- 插播一个很低级的错误 太久没写了
<div class="ccircle"></div>
var ccircle = document.getElementsByClassName("ccircle")
ccircle.style.backgroundColor = 'red'
这样写的时候一直报错,把我气死了…
但是都不知道凭什么报错, 就把ccircle这个对象输出了一下
才反应过来!!!可以有无数个元素取ccircle
这个类名。所以 他获取完是一个数组对象啊!!! 所以咱们后面要加上[0]
var ccircle = document.getElementsByClassName("ccircle")[0]
Dom和Bom的概念
这里插播一个面试题, 用友面试的时候被问到了,但是太久没看 记不清了
- Dom(Document Object Model) 文档对象模型
HTML DOM定义了访问和操作HTML 文档的标准方法
自己的理解就是,
<div id="box"></div>
var box = document.getElementById("#box")
box.innerHTML = "..."
获取这个dom对象,对其进行一个操作
- Bom(Browser Object Model) 浏览器对象模型
作用:弹出新的浏览器窗口、移动、关闭浏览器窗口及调整浏览器窗口大小