JavaScript执行环境是单线程的,所以同一个时间只能执行一次任务,后面任务队列都等待着前一个任务执行完毕才能够执行,为了解决这个问题,Javascript将任务分为同步和异步两种执行模式
这是最基本的异步处理方式了
//加入两个函数
f1() ---耗时很长 会阻塞后面代码
f2()
//改写f1
funtion f1(callback){
setTimeout(function(){
//f1代码
callback()
})
}//执行代码就编程这个样子 f1(f2);
采用这种方式,就可以把同步编程异步操作了,f1不会阻塞任何程序,相当于执行了程序的主要逻辑,但是代码高度耦合,流程会很乱,而且每个人物只能指定一个回调函数
这种方式采用的是事件驱动,这种方式不会考虑代码编写顺序,而是取决于某个时间是否触发。
f1.on(‘done‘,f2);//注册监听
funtioin f1(){
setTimeout(function(){
f1.trigger("done") //触发done,执行f2
})
}
这种方法有点很明显,可以绑定多个事件,每个事件指定多个回调,而且可以去耦合,有利于实现模块化,缺点是过度依赖驱动,事件流程变得不清晰。
上一节的"事件",完全可以理解成"信号"。
我们假定,存在一个"信号中心",某个任务执行完成,就向信号中心"发布"(publish)一个信号,其他任务可以向信号中心"订阅"(subscribe)这个信号,从而知道什么时候自己可以开始执行。这就叫做"发布/订阅模式"(publish-subscribe pattern),又称"观察者模式"(observer pattern)。这个模式有多种实现,下面采用的是Ben Alman的Tiny Pub/Sub,这是jQuery的一个插件。
首先,f2向"信号中心"jQuery订阅"done"信号。
jQuery.subscribe("done", f2);
然后,f1进行如下改写:
jQuery.subscribe("done", f2);
function f1(){
setTimeout(function () {
// f1的任务代码
jQuery.publish("done");
}, 1000);
}
jQuery.publish("done")的意思是,f1执行完成后,向"信号中心"jQuery发布"done"信号,从而引发f2的执行。
此外,f2完成执行后,也可以取消订阅(unsubscribe)。
jQuery.unsubscribe("done", f2);
这种方法的性质与"事件监听"类似,但是明显优于后者。因为我们可以通过查看"消息中心",了解存在多少信号、每个信号有多少订阅者,从而监控程序的运行。
这个实例化之后无论成功或者失败,都会返回一个函数供接下来的(then
error
)等操作使用
new Promiss((resole,reject) => {
//f1代码
//成功回调 resolveI(参数) 或者 失败回调 reject(回调)
}).then( () => {
//接下来操作
})
理解next()使用
总结流程:
(1)执行next后会从上往下依次返回每个yield表达式的值,
(2)如果next有传参的话,会整个覆盖掉将要返回当前yield的上一个yield,
(3)方法内的yield表达式和return都执行完了,就会直接返回undefined了。
入参 分析结果
1 1(无论是否传参,传什么参数,返回第一个表达式的值1)
3 3(返回第二个表达式的值yield a,a=上一个yield表达式yield 1,被参数3覆盖,所以a=3)
4 4(返回第三个表达式的值yield b,b=上一个yield表达式yield a,被参数4覆盖,所以b=4)
5 12(返回return a+b+c,c=上一个yield表达式yield b,被参数5覆盖,所以c=5,也就是a+b+c=3+4+5=12)
这下没错了,太不容易了
解决异步
const fs = require(‘fs‘)
// Promise 版的readFile
const readFile = function (fileName) {
return new Promise(function(resolve, reject) {
fs.readFile(fileName, function(err, data){
if (err) return reject(error);
resolve(data);
})
})
}
const gen = function * () {
let f1 = yield readFile(‘a.txt‘);
let f2 = yield readFile(‘b.txt‘);
console.log(‘F1--->‘, f1.toString());
console.log(‘F2--->‘, f2.toString());
}
// 基于 Generator 和 Promise 的自动执行器
function run(gen) {
let g = gen();
function next(data) {
let result = g.next(data);
if (result.done) return result.value;
result.value.then(function(data) {
next(data);
});
}
next();
}
run(gen);
await 所在的那一行语句是同步的,将会等待当前这一步的执行结果
const fs = require(‘fs‘)
// Promise 版的readFile
const readFile = function (fileName) {
return new Promise(function(resolve, reject) {
fs.readFile(fileName, function(err, data){
if (err) return reject(err);
resolve(data);
})
})
}
const asyncReadFile = async function () {
const f1 = await readFile(‘a.txt‘);
const f2 = await readFile(‘b.txt‘);
console.log(f1.toString());
console.log(f2.toString());
};
asyncReadFile();
整体是一个异步函数 不难理解。在实现上,我们不妨逆向一下,语言层面让async关键字调用时,在函数执行的末尾强制增加一个promise 反回:内部是同步的 是怎么做到的?实际上 await 调用,是让后边的语句(函数)做了一个递归执行,直到获取到结果并使其 状态 变更,才会 resolve 掉,而只有 resolve 掉,await 那一行代码才算执行完,才继续往下一行执行。
原文:https://www.cnblogs.com/yanzq-x/p/13927510.html