总是纠结js是异步还是同步?
对于JS 异步还是同步这个问题,不需要纠结太多,在执行DOM渲染
时,确实是同步执行的,也是为了安全起见,一步一步执行,如果上一步未完成,下一步是不会运行的。
但本质还是单线程
但是对于 网络请求 这样的场景,一个网络资源啥时候返回,这个时间是不可预估的,所以不能傻傻的等着,也就是这样,设计了异步,不管返回结果,执行后就执行下一步,上一步的执行结果什么时候返回,就什么时候再返回。
实现异步的最核心原理,就是将callback
作为参数传递给异步执行函数,当有结果返回之后再触发callback
执行
常见的异步操作:
- 网络请求, 如
ajax
,http.get
- IO 操作, 如
readFile
,readdir
- 定时函数, 如
setTimeout
,setInterval
网络请求实现发展:
1、回调 2、promise 3、Generator 4、async/await
回调
对于这种传递过去不执行,等出来结果之后再执行的函数,叫做callback
,即回调函数,如ajax
操作中
使用场景:
- 事件回调
Node API
setTimeOut/setInterval
中的回调函数ajax
请求
优点: 简单;
缺点: 不能 try catch
; 产生回调地狱
使用
// 比较常见的有ajax
$.ajax('http://www.wyunfei.com/', {
success (res) {
// 这里可以监听res返回的数据做回调逻辑的处理
}
})
// 或者在页面加载完毕后回调
$(function() {
// 页面结构加载完成,做回调逻辑处理
})
promise
承诺未来会执行,有三种状态,分别是: pedding
未完成, resolved
成功, rejected
失败。
状态改变,只有两种情况:
pedding
->resolved
pedding
->rejected
。当promise
状态发生改变,就会触发then()
里的响应函数处理后续步骤,.then()
返回一个新的promise实例,所以可以链式调用
特点:
- 状态一经改变,不会再变化
- 异步操作可以简化为同步操作,避免层层调用
从表面上看,可以解决回调地狱的问题,但是实际上并没有解决,在使用中,仍然需要有.then()的不断调用
缺点:
- 不能取消
promise
- 不能
try catch
pedding
状态时,不知道现在进展到哪一个阶段
Promise.all([1,2,3])
可以实现多个异步并行执行,同一时刻获取最终结果的问题,当子Promise
全部完成,该Promise
完成,返回全部值的数组;当有一个子promise
失败,该promise
失败,返回第一个失败的结果。
Promise.race()
同上,但只要有一个成功,就返回成功的结果
使用:
new Promise(function(resolve, reject) {
// 一段耗时的一步操作
resolve('success');
// reject('fail');
}).then(
(res)=>{console.log(res)},
(err)=>{console.log(err)}
)
Generator
generator
和函数不同的是,generator
由function* 定义
(注意多出的*号),并且,除了return
语句,还可以用yield
返回多次;可以在执行过程中多次返回
使用 .next()
next
方法可以带一个参数,该参数就会被当作上一个yield
表达式的返回值。每一次的next()
调用,执行一次yield
使用
function* gen() {
let a = yield 111;
console.log(a);
let b = yield 222;
console.log(b);
let c = yield 333;
console.log(c);
let d = yield 444;
console.log(d);
}
let t = gen();
//next方法可以带一个参数,该参数就会被当作上一个yield表达式的返回值
t.next(1); //第一次调用next函数时,传递的参数无效
t.next(2); //a输出2;
t.next(3); //b输出3;
t.next(4); //c输出4;
t.next(5); //d输出5;
try {
// r1 = yield ajax('http://url-1', data1);
// r2 = yield ajax('http://url-2', data2);
// r3 = yield ajax('http://url-3', data3);
// success(r3);
}
catch (err) {
// handle(err);
}
async/await
其实就是实现了将 Generator
函数和自动执行器(co)
,包装在一个函数中
基本兼容上面异步方式的 缺点
使用
const fs = require('fs');
const bluebird = require('bluebird');
const readFile = bluebird.promisify(fs.readFile);
async function read() {
await readFile(A, 'utf-8');
await readFile(B, 'utf-8');
await readFile(C, 'utf-8');
//code
}
read().then((data) => {
//code
}).catch(err => {
//code
});
关注我获取更多前端资源和经验分享
感谢大佬们阅读,希望大家头发浓密,睡眠良好,情绪稳定,早日实现财富自由~