摘要:回调的问题异常处理异步代码时不再生效捕获错误因为这个回调函数被存放了起来,直到下一个事件环的时候才会取出只能捕获当前循环内的异常,对异步无能为力。
异步
所谓"异步",简单说就是一个任务分成两段,先执行第一段,然后转而执行其他任务,等做好了准备,再回过头执行第二段,比如,有一个任务是读取文件进行处理,异步的执行过程就是下面这样。高阶函数这种不连续的执行,就叫做异步。相应地,连续的执行,就叫做同步。
函数作为一等公民,可以作为参数和返回值可以用于批量生成函数
let toString = Object.prototype.toString; let isString = function (obj) { return toString.call(obj) == `[object String]`; } let isFunction = function (obj) { return toString.call(obj) == `[object Function]`; } let isType = function (type) { return function (obj) { return toString.call(obj) == `[object ${type}]`; } }可以用于需要调用多次才执行的函数
let after = function(times,task){ return function(){ if(times--==1){ return task.apply(this,arguments); } } } let fn = after(3,function(){ console.log(3);}); fn();异步编程的语法目标,就是怎样让它更像同步编程,有以下几种
回调函数实现
事件监听
发布订阅
Promise/A+ 和生成器函数
async/await
回调所谓回调函数,就是把任务的第二段多带带写在一个函数里面,等到重新执行这个任务的时候,就直接调用这个函数
fs.readFile("某个文件", function (err, data) { if (err) throw err; console.log(data); });
这是一个错误优先的回调函数(error-first callbacks),这也是Node.js本身的特点之一。
回调的问题 异常处理try{ //xxx }catch(e){//TODO} 异步代码时try catch不再生效 let async = function(callback){ try{ setTimeout(function(){ callback(); },1000) }catch(e){ console.log("捕获错误",e); } } async(function(){ console.log(t); });
因为这个回调函数被存放了起来,直到下一个事件环的时候才会取出,try只能捕获当前循环内的异常,对callback异步无能为力。
Node在处理异常有一个约定,将异常作为回调的第一个实参传回,如果为空表示没有出错。
async(function(err,callback){ if(err){ console.log(err); } });
异步方法也要遵循两个原则
必须在异步之后调用传入的回调函数
如果出错了要向回调函数传入异常供调用者判断
let async = function(callback){ try{ setTimeout(function(){ if(success) callback(null); else callback("错误"); },1000) }catch(e){ console.log("捕获错误",e); } }回调地狱
异步多级依赖的情况下嵌套非常深,代码难以阅读的维护
let fs = require("fs"); fs.readFile("template.txt","utf8",function(err,template){ fs.readFile("data.txt","utf8",function(err,data){ console.log(template+" "+data); }) })异步流程解决方案 事件发布/订阅模型
订阅事件实现了一个事件与多个回调函数的关联
let fs = require("fs"); let EventEmitter = require("events"); let eve = new EventEmitter(); let html = {}; eve.on("ready",function(key,value){ html[key] = value; if(Object.keys(html).length==2){ console.log(html); } }); function render(){ fs.readFile("template.txt","utf8",function(err,template){ eve.emit("ready","template",template); }) fs.readFile("data.txt","utf8",function(err,data){ eve.emit("ready","data",data); }) } render();哨兵变量
let fs = require("fs"); let after = function(times,callback){ let result = {}; return function(key,value){ result[key] = value; if(Object.keys(result).length==times){ callback(result); } } } let done = after(2,function(result){ console.log(result); }); function render(){ fs.readFile("template.txt","utf8",function(err,template){ done("template",template); }) fs.readFile("data.txt","utf8",function(err,data){ done("data",data); }) } rendePromise/Deferred模式 生成器Generators/ yield
当你在执行一个函数的时候,你可以在某个点暂停函数的执行,并且做一些其他工作,然后再返回这个函数继续执行, 甚至是携带一些新的值,然后继续执行。
上面描述的场景正是JavaScript生成器函数所致力于解决的问题。当我们调用一个生成器函数的时候,它并不会立即执行, 而是需要我们手动的去执行迭代操作(next方法)。也就是说,你调用生成器函数,它会返回给你一个迭代器。迭代器会遍历每个中断点。
next方法返回值的value属性,是Generator函数向外输出数据next方法还可以接受参数,这是向 Generator 函数体内输入数据
function* foo () { var index = 0; while (index < 2) { yield index++; //暂停函数执行,并执行yield后的操作 } } var bar = foo(); // 返回的其实是一个迭代器 console.log(bar.next()); // { value: 0, done: false } console.log(bar.next()); // { value: 1, done: false } console.log(bar.next()); // { value: undefined, done: true }
Coco是一个为Node.js和浏览器打造的基于生成器的流程控制工具,借助于Promise,你可以使用更加优雅的方式编写非阻塞代码。
let fs = require("fs"); function readFile(filename) { return new Promise(function (resolve, reject) { fs.readFile(filename, function (err, data) { if (err) reject(err); else resolve(data); }) }) } function *read() { let template = yield readFile("./template.txt"); let data = yield readFile("./data.txt"); return template + "+" + data; } co(read).then(function (data) { console.log(data); }, function (err) { console.log(err); }); function co(gen) { let it = gen(); return new Promise(function (resolve, reject) { !function next(lastVal) { let {value, done} = it.next(lastVal); if (done) { resolve(value); } else { value.then(next, reason => reject(reason)); } }(); }); }Async/ await
使用async关键字,你可以轻松地达成之前使用生成器和co函数所做到的工作Async的优点
内置执行器
更好的语义
更广的适用性
let fs = require("fs"); function readFile(filename) { return new Promise(function (resolve, reject) { fs.readFile(filename, "utf8", function (err, data) { if (err) reject(err); else resolve(data); }) }) } async function read() { let template = await readFile("./template.txt"); let data = await readFile("./data.txt"); return template + "+" + data; } let result = read(); result.then(data=>console.log(data));
async 函数的实现
async 函数的实现,就是将 Generator 函数和自动执行器,包装在一个函数里。
async function read() { let template = await readFile("./template.txt"); let data = await readFile("./data.txt"); return template + "+" + data; }
// 等同于 function read(){ return co(function*() { let template = yield readFile("./template.txt"); let data = yield readFile("./data.txt"); return template + "+" + data; }); } async_function- generator
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/101790.html
摘要:异步时序问题吾辈的博客原文场景死后我们必升天堂,因为活时我们已在地狱。关键点异步操作得到结果的时间顺序是不确定的如果触发事件的频率较高异步操作的时间过长出现这种问题怎么解决既然关键点由两个要素组成,那么,只要破坏了任意一个即可。 JavaScript 异步时序问题 吾辈的博客原文:https://blog.rxliuli.com/p/de... 场景 死后我们必升天堂,因为活时我们已...
摘要:同步与异步以上为同步代码,函数必须等函数执行完毕后才能执行。异步回调产生的结果就是,函数的调用并不直接返回结果,而往往是交给回调函数进行异步处理。 同步与异步: function a(){} function b(){} a(); b(); 以上为同步代码,函数b必须等函数a执行完毕后才能执行。 function a(){ ...
摘要:同步和异步先说个傻子的故事有个傻子,第一次用某雷下载大片,就是大人看的片,咳咳咳。。。 1.同步和异步 1.1先说个傻子的故事 有个傻子,第一次用某雷下载大片,就是大人看的片,咳咳咳。。。 某雷告诉他,下载时间要俩小时,傻子心想,要俩小时呐,我第一次用某雷,我得盯着它下载,啥也不能干 于是傻子就干瞪着电脑,等着片下完,这俩小时,傻子啥也没干 后来,傻子变聪明了,他想,反正某雷在帮他下...
摘要:事件循环事件循环是指主线程重复从消息队列中取消息执行的过程。事件触发时,表示异步任务完成,会将事件监听器函数封装成一条消息放到消息队列中,等待主线程执行。 一. 单线程 我们常说JavaScript是单线程的。 所谓单线程,是指在JS引擎中负责解释和执行JavaScript代码的线程只有一个。不妨叫它主线程。 但是实际上还存在其他的线程。例如:处理AJAX请求的线程、处理DOM事件的线...
摘要:例如处理请求的线程处理事件的线程定时器线程读写文件的线程例如在中等等。事件循环事件循环是指主线程重复从消息队列中取消息执行的过程。事件触发时,表示异步任务完成,会将事件监听器函数封装成一条消息放到消息队列中,等待主线程执行。 一. 单线程 我们常说JavaScript是单线程的。 所谓单线程,是指在JS引擎中负责解释和执行JavaScript代码的线程只有一个。不妨叫它主线程。 但是实...
阅读 3344·2021-11-10 11:36
阅读 3244·2021-10-08 10:21
阅读 2841·2021-09-29 09:35
阅读 2416·2021-09-22 16:06
阅读 3959·2021-09-09 09:33
阅读 1327·2019-08-30 15:44
阅读 3171·2019-08-30 10:59
阅读 2982·2019-08-29 15:32