目录
- 如何实现sleep的效果(es5或者es6)
- 箭头函数中this指向举例
- Promise.allSettled的实现
- 事件循环demo-【promise中是否执行了resolve或者reject】
构造函数与class内部this的区别
- 疑问: 五题中 2)的第一段的代码执行是undefined的原因是?
一、如何实现sleep的效果(es5或者es6)
(1)while循环的方式
function sleep(ms){
var start=Date.now(),expire=start+ms;
while(Date.now()<expire);
console.log('1111');
return;
}
执行sleep(1000)之后,休眠了1000ms之后输出了1111。上述循环的方式缺点很明显,容易造成死循环。
(2)通过promise来实现
function sleep(ms){
var temple=new Promise(
(resolve)=>{
console.log(111);setTimeout(resolve,ms)
});
return temple
}
sleep(500).then(function(){
//console.log(222)
})
//先输出了111,延迟500ms后输出222
(3)通过async封装
function sleep(ms){
return new Promise((resolve)=>setTimeout(resolve,ms));
}
async function test(){
var temple=await sleep(1000);
console.log(1111)
return temple
}
test();
//延迟1000ms输出了1111
(4).通过generate来实现
function* sleep(ms){
yield new Promise(function(resolve,reject){
console.log(111);
setTimeout(resolve,ms);
})
}
sleep(500).next().value.then(function(){console.log(2222)})
二、 箭头函数中this指向举例
箭头函数定时绑定,外层函数的this为自己的this
1)普通函数
var a=11;
function Test2(){
this.a=22;
console.log('this1:', this);
let b=function(){
console.log('this2:', this);
console.log(this.a);
};
setTimeout(function(){
console.log('this3:', this);
console.log(this.a);
},1000);
b();
}
var t1=new Test2();
可以看到
构造函数的内部函数的this全部指向了 window
2)构造函数中的函数改为箭头函数
var a=11;
function Test2(){
this.a=22;
console.log('this1:', this);
let b=()=>{
console.log('this2:', this);
console.log(this.a);
};
setTimeout(()=>{
console.log('this3:', this);
console.log(this.a);
},1000);
b();
}
var t1=new Test2();
可以看到
构造函数内部的箭头函数的this全部指向了他的外层构造函数Test2。
三、Promise.allSettled的实现
1) 回顾: Promise 状态
给定一个返回Promise的异步操作,以下这些是Promise的可能状态:
- pending: 初始状态,既不是成功,也不是失败状态。
- fulfilled: 意味着操作成功完成。
- rejected: 意味着操作失败。
- Settled:
Promise要么被完成,要么被拒绝。Promise一旦达成,它的状态就不再改变。
1.1) 什么是组合
又称部分-整体模式,将对象整合成树形结构以表示“部分整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性,它基于两种函数:
- 基元函数(简短:基元)创建原子块。
- 组合函数(简称:组合)将原子和/或复合件组合在一起以形成复合件。
对于 JS 的 Promises 来说
- 基元函数包括:
Promise.resolve()、Promise.reject() - 组合函数:
Promise.all(),Promise.race(),Promise.allSettled()
2) 实现 allSettled
allSettled 对于每个结果对象,都有一个 status 字符串。如果它的值为 fulfilled,则结果对象上存在一个 value 。如果值为 rejected,则存在一个 reason 。value(或 reason )反映了每个 promise 决议(或拒绝)的值。
MyPromise.allSettled = function (promises) {
return new MyPromise((resolve, reject) => {
promises = Array.isArray(promises) ? promises : []
let len = promises.length
const argslen = len
// 如果传入的是一个空数组,那么就直接返回一个resolved的空数组promise对象
if (len === 0) return resolve([])
// 将传入的参数转化为数组,赋给args变量
let args = Array.prototype.slice.call(promises)
// 计算当前是否所有的 promise 执行完成,执行完毕则resolve
const compute = () => {
if(--len === 0) {
resolve(args)
}
}
function resolvePromise(index, value) {
// 判断传入的是否是 promise 类型
if(value instanceof MyPromise) {
const then = value.then
then.call(value, function(val) {
args[index] = { status: 'fulfilled', value: val}
compute()
}, function(e) {
args[index] = { status: 'rejected', reason: e }
compute()
})
} else {
args[index] = { status: 'fulfilled', value: value}
compute()
}
}
for(let i = 0; i < argslen; i++){
resolvePromise(i, args[i])
}
})
}
四、事件循环demo
1) demo1
需要注意,
Promise构造器中,resolve()的位置,在Promise的构造器中无论是在resolve前或者后,都是与同步任务一样去执行的。只有then中的才是 微任务。
console.log('begin')
setTimeout(function () {
console.log('setTimeout 0');
});
new Promise(function (resolve) {
console.log('promise1');
for (let i = 0; i < 1000; i++) {
i === 99 && resolve();
}
console.log('promise2');
}).then(function () {
console.log('then1');
setTimeout(() => {
console.log('setTimeout2 between promise1&2')
})
}).then(() => {
console.log('promise 3')
});
console.log('end')
2) demo2 Promise状态是pending 没有resolve,也没有reject。
导致成功和失败的回调都不会被执行。因为在Promise的实现中只有在构造器中执行了resolve或者reject。状态成会变更。才会赋值。 注意这里注释了resolve。导致then后面的成功CB不会被执行。
console.log('begin')
setTimeout(function () {
console.log('setTimeout 0');
});
new Promise(function (resolve) {
console.log('promise1');
// resolve() // 注意这里注释了resolve。导致then后面的成功CB不会被执行。
console.log('promise2');
}).then(function () {
console.log('then1');
setTimeout(() => {
console.log('setTimeout2 between promise1&2')
})
}).then(() => {
console.log('promise 3')
}).catch((err)=>{
console.log('reject:', err)
});
console.log('end')
3) demo3 Promise.reject()
实例化时自执行函数执行了reject,那么,失败回调会被执行。
reject失败回调,首先会在then中会被捕获,其次才会在catch中会被捕获。 如果then中捕获了,catch将不会在捕获。
console.log('begin')
setTimeout(function () {
console.log('setTimeout 0');
});
new Promise(function (resolve,reject) {
console.log('promise1');
// resolve() // 注意这里注释了resolve。导致then后面的成功CB不会被执行。
reject(0);
console.log('promise2');
}).then(function () {
console.log('then1');
setTimeout(() => {
console.log('000')
})
}).then(() => {
console.log('promise 3')
},(err)=>{
console.log('第二个then中的reject:', err)
}).catch((err)=>{
console.log('catch 中 reject:', err)
});
console.log('end')
五 构造函数与class 内部this的区别
1) 构造函数内部this
window.name = 'aaa';
function Atest1(){
this.name = 123;
};
Atest1.prototype={
getA() {
console.log(this);
return this.name + 1;
},
getB:()=>{
console.log(this);
return this.name + 1;
}
}
let a = new Atest1();
let funcA = a.getA;
let funcB = a.getB;
funcA();
funcB();
此调用方式,相当于
window.funcA(),所以,无论原型上的方法是否是箭头函数。那么,this,指向的都是widow。
换一种调用方式
window.name = 'aaa';
function Atest1(){
this.name = 123;
};
Atest1.prototype={
getA() {
console.log(this,this.name);
return this.name + 1;
},
getB:()=>{
console.log(this);
return this.name + 1;
}
}
let a = new Atest1();
let funcA = a.getA();
这种调用方式很明显,
getA是a调用的,所以指向a
箭头函数
理论上箭头函数如果是普通函数的话 其中的this 会指向 a,实际上因为是箭头函数所以指向的是 window。
a.getB();
这种调用方式很明显,
getA是a调用的,所以指向a
2)(?) class内部this
window.name = 'aaa';
class Atest {
constructor() {
this.name = 123;
}
getA() {
console.log(this);
return this.name + 1;
}
getB=()=>{
console.log(this);
return this.name + 1;
}
};
let a = new Atest();
let funcA = a.getA;
let funcB = a.getB;
funcA();
funcB();
class中此种调用方式this 指向的是undefined。首先和
super()没有关系,super是子类当中使用的。
感谢评论区同学给的建议
调用时改为window.funA()时,才能让class中的this指向window,理论上默认funA应该就是在window上吧?
常规对象方式调用
window.name = 'aaa';
class Atest {
constructor() {
this.name = 123;
}
getA() {
console.log(this);
return this.name + 1;
}
getB=()=>{
console.log(this);
return this.name + 1;
}
};
let a = new Atest();
a.getA();
a.getB();
参考
总结
箭头函数定时绑定外层函数的this为自己的this- 每一个函数都是一个
独立的盒子,都有自己的this,比如函数嵌套时,函数返回函数时,函数做为参数时。除了箭头函数是定义时绑定外层函数的this。其他场景都是看当前函数是如何调用的,从而决定this的指向 - 需要注意,
Promise构造器中,resolve()的位置,在Promise的构造器中无论是在resolve前或者后,都是与同步任务一样去执行的。只有then中的才是 微任务。 - 注意:
promise实例化传入的自执行成功或者失败回调不执行的话。会导致then``成功和失败的回调都不会被执行。因为在Promise的实现中只有在构造器中执行了resolve或者reject。状态成会变更。才会赋值。 reject失败回调,首先会在then中会被捕获,其次才会在catch中会被捕获。如果then中捕获了,catch将不会在捕获
疑问
- 五题中 2)的第一段的代码执行是undefined的原因是?