js 是单线程还是多线程? 单线程,单位时间内只能处理一个进程、let 和 var 声明变量的区别、async/await 的使用方式和场景、谈谈对 promise 的理解、箭头函数有什么作用和实际应用场景
1-js 是单线程还是多线程?
单线程,单位时间内只能处理一个进程
JavaScript语言的一大特点就是单线程,也就是说,同一个时间只能做一件事,为了利用多核CPU的计算能力,HTML5提出Web Worker标准,允许JavaScript脚本创建多个线程,但是子线程完 全受主线程控制,且不得操作DOM。所以,这个新标准并没有改变JavaScript单线程的本质。
2-let 和 var 声明变量的区别?
js中let和var定义变量的区别,主要体现在作用于的不同。
var定义的变量是全局变量或者函数变量。
let定义的变量是块级的变量。
例如:
while(1){
let let1 = 2;
var var1 = 2;
}
alert(let1); //不可访问
alert(var1); //可以访问
也就是说,let只对它所在的最内侧块内有效,而var的范围至少是一个函数之内。
var定义的变量是全局变量或者函数变量。
let定义的变量是块级的变量。
例如:
while(1){
let let1 = 2;
var var1 = 2;
}
alert(let1); //不可访问
alert(var1); //可以访问
也就是说,let只对它所在的最内侧块内有效,而var的范围至少是一个函数之内。
3-说说 async/await 的使用方式和场景
假设我们有如下两个方法:
function convertToBase64Data(url) { // 转成base64格式
return new Promise( resolve => {
setTimeout( () => {
resolve('img');
}, 1000);
});
}
function saveToLocal(img) { // 保存到本地
return new Promise( resolve=> {
setTimeout( () => {
resolve('success');
}, 200);
});
}
场景1:多个异步需要按顺序:图片处理完成然后保存在本地
用promise我们可能这样写:
function fn1() {
return convertToBase64Data('http://1.jpg').then( base64Data => {
return saveToLocal(base64Data);
})
}
使用await则更简洁,更好理解:
async function fn1() {
const base64Data = await download('http://1.jpg');
const result = await saveToLocal(base64Data);
return result;
}
场景2:图片需要同时处理,但是要按顺序一张一张保存在本地
不使用await:
function fn2() {
const promise1 = convertToBase64Data('http://1.jpg');
const promise2 = convertToBase64Data('http://1.jpg');
Promise.all([promise1,promise2]).then( datas => {
saveToLocal(datas[0]).then( result1 => {
saveToLocal(datas[1]).then(result2 => {
console.log(result2);
})
})
})
}
我们看到,回调很多,很不方便,下面是使用await:
async function fn2() {
// 同时处理两张
const promise1 = convertToBase64Data('http://1.jpg');
const promise2 = convertToBase64Data('http://2.jpg');
const [data1, data2] = await Promise.all([promise1, promise2]);
// 先保存第一张
const result = await saveToLocal(data1);
// 再保存第二张
const result2 = await saveToLocal(data2);
}
代码层次很清晰,很容易阅读。
场景3:多张图片,处理一张保存一张,然后才能处理下一张
不使用await:
// 你来写写看!!!
使用await:
async function fn3() {
const imgUrls = ['http://1.jpg', 'http://2.jpg', 'http://3.jpg', 'http://4.jpg', 'http://5.jpg'];
for (let i = 0; i < imgUrls.length; i++) {
const base64Data = await convertToBase64Data(imgUrls[i]);
const result = await saveToLocal(base64Data);
console.log(result);
}
}
是不是觉得很爽?
场景4:条件语句
不使用await:
function fn4(needConvertToBase64) {
return download('http://1.jpg').then( img => {
if (needConvertToBase64) {
return convertToBase64(img).then(base64Data => {
return base64Data;
});
} else {
return img;
}
});
}
return 到让人迷茫。下面使用await, 这就很爽:
async function fn4(needConvertToBase64) {
const img = await download('http://1.jpg');
if (needConvertToBase64) {
const base64Data = await convertToBase64(img);
return base64Data;
}
return img;
}
场景5: 你可能会这样:调用方法1,使用方法1返回的结果去调用方法2,然后使用两者的结果去调用方法3。
假设有如下业务: 获取用户ID,然后根据ID获取用户信息,然后将两者保存在服务器。
function getUserId() {
return Promise.resolve('123123');
}
function getUserInfo(id) {
return Promise.resolve({name: 'aaron'});
}
function saveToServer(id, userInfo) {
return Promise.resolve('success');
}
你的代码很可能是这样的:
function fn5() {
return getUserId().then( id => { // 拿到id
return getUserInfo(id).then( userInfo => {
return saveToServer(id, userInfo);
});
});
}
使用await:
async function fn5() {// 使用await
const id = await getUserId();
const userInfo = await getUserInfo(id);
return saveToServer(id, userInfo);
}
场景6:错误处理
不使用await,try/catch不能捕获saveToLocal的错误,convertToBase64 的Promise中,只能.catch处理,这样错误处理代码非常冗余,使代码很复杂:
function fn6() {
try {
convertToBase64('http://1.jpg').then( data => {
// saveToLocal可能会出错
saveToLocal(data).then( result => {
console.log(result);
});
// .catch(err => { console.log(err)}); // 只能在.catch中处理
});
} catch (err) { // 这里取不到saveToLocal的错误
console.log(err);
}
}
使用await,try/catch能捕获saveToLocal的错误:
async function fn6() {
try {
const data = await convertToBase64('http://1.jpg');
const result = await saveToLocal(data);
console.log(result);
} catch (err) {
console.log(err);
}
}
4-谈谈对 promise 的理解
1.代码结构更加扁平且更可读,清晰明了。
2.能解决回调地狱问题。
3.可将数据请求和业务逻辑分离开来。
4.便于管理维护。
5.能更好的捕获错误。
6.Promise 是一个构造函数,对回调函数的一种封装,对异步编程的一种改进,用同步的方式表达出来。
5-箭头函数有什么作用和实际应用场景?
- 箭头函数适合于无复杂逻辑或者无副作用的纯函数场景下,例如:用在 map、reduce、filter 的回调函数定义中
- 箭头函数的亮点是简洁,但在有多层函数嵌套的情况下,箭头函数反而影响了函数的作用范围的识别度,这种情况不建议使用箭头函数
- 箭头函数要实现类似纯函数的效果,必须剔除外部状态。所以箭头函数不具备普通函数里常见的 this、arguments 等,当然也就不能用 call()、apply()、bind() 去改变 this 的指向
-
箭头函数不适合定义对象的方法(对象字面量方法、对象原型方法、构造器方法),因为箭头函数没有自己的 this,其内部的 this 指向的是外层作用域的 this
const json = { bar: 1, fn: () => console.log(this.bar) }; json.fn(); //-> undefined // this 并不是指向 json 这个对象,而是再往上到达全局作用域function Foo() { this.bar = 1; } Foo.prototype.fn = () => console.log(this.foo); const foo = new Foo(); foo.fn(); //-> undefined // this 并不是指向 Foo,根据变量查找规则,回溯到了全局作用域const Message = (text) => { this.text = text; }; var helloMessage = new Message('Hello World!'); console.log(helloMessage.text); //-> Message is not a constructor // 不可以当作构造函数,也就是说,不可以使用 new 命令 -
箭头函数不适合定义结合动态上下文的回调函数(事件绑定函数),因为箭头函数在声明的时候会绑定静态上下文
const button = document.querySelector('button'); button.addEventListener('click', () => { this.textContent = 'Loading...'; }); // this 并不是指向预期的 button 元素,而是 window

浙公网安备 33010602011771号