用nodejs开发的时候,总会碰到一些莫明其妙的问题,排查到最后,才发现是异步搞的鬼
比如:
- nodejs里的for循环是异步的吗?
- 可以总结为带有回调的都是异步的吗?好像不能这样记,nodejs api里有个读取文件的方法就分为 readFile readFileSync,可气的是它们都是有回调的
有大佬能不吝赐教讲解一下吗?跪谢!
另外还有一个问题,循环一个集合有很多方法,for, each, forEach, map等,这些东西里哪些是nodejs内置的?哪些是jquery里的?哪些是es规范里的呢?它们都是同步的还是异步的呢?
还请原谅我这小白的问题,相信很多学习nodejs的朋友都有过这样的疑惑 :joy
补充:
虽然现在 ES 标准里加上了 async await 来实现同步操作,还有 Promise,但业务复杂了,代码还是会被各种回调弄的执行流程出问题
举个例子
写 js 的时候用的最多的应该就是回调了,回调里可以传很多个参数,简单的操作,这样写很方便,但业务复杂了,就不方便了,回调地狱也就是这样来的
这时候你可能会说不是有 Promise 吗,但用这货我觉得也就是把代码变的好看些,拿结果还是要靠 then 方法回调拿
到这你可能还会说,不是还有 async await 吗,这货确实不用从 then 函数的回调里拿数据了,但用 nodejs 多了就会发现,很多函数的调用的写法还是会用到回调,而且这时候还会在回调函数的前面加上个 async,我也是无语了,这不是又回到起点了吗,如下
it ('waitBody', async function() {
await driver.sleep(500).wait('body', 30000).html().then(function(code) {
isPageError(code).should.be.false;
})
})
当然也有用起来舒服的地方,比如 mongoose 的查询
const results = await UserModel.find({});
综上,难道就没有一个优雅的方法能让代码一行一行的执行吗,前一个结果执行完了,拿到结果再参与下一行代码的执行?
有人会说了,你上面不是说了 async await 了吗,它不就是这样用的吗?那为啥还要在回调的方法上用 async await 呢?总觉得有点换汤不换药,折腾来折腾去,还是离不了回调,但回调又会涉及到代码结构和流程控制上的问题
兄弟貌似一脑子浆糊,需要加强基础 。 可以参考下 阮一峰 的相关博客文章呵呵
- nodejs 里面的 for 是 ECMA 原生的命令,同步
- 多数情况下带有回调函数的是异步,不过 readFile 的确是带有回调函数参数的同步,因为同步函数也能介绍回调函数参数。
- for, each, forEach, map 这些都是 ECMA 规范里面的。 node.js 、浏览器各自实现功能。
兄弟,你是大佬假装的萌新吗?3000多分的人了不可能问这种问题吧?
@waitingsong 感谢,确实是一脑子浆糊,一直没有理清楚这里面的问题,确实要加强一下基础了。。感谢大佬指点
@Gitforxuyang 不是大佬,真萌新,分数都是早期水的 😂
我是这样理解的:
- 原生的循环类的一般都是同步堵塞的
- 自己写的方法,要看函数说明或注释,返回promise就可以用await,有callback参数就是回调, (如果不写注释是比较费劲的!)
- async函数就是内部允许用await调用其它方法并返回promise而已
如有不对,请指正
确实有很多新手一脑子浆糊,如果我们看到 fs.copyFileSync
那么就知道这个函数是同步的,对应的 fs.copyFile
是异步的。
如果我们看到一个函数,比如 fn_abc
,我们怎么知道这个函数是同步还是异步呢?只能看文档或者代码,因为我们从签名中无法知道这个函数是同步还是异步。
回调只是一种写法,并不能区分是同步还是异步。Node.js 创建之初,既没有 yield,也没有 async/awai,唯一能用的异步处理方式就是回调。
我觉得以后的编码风格会慢慢变为:同步使用 callback,异步使用 async/awai。
@justjavac 感谢,看来写nodejs还是要靠经验呀,用的多了,就知道了,也就用的顺手了
@tomoya92 我觉得 jjc 大神说的没有你那层意思,是你自己总结的… 还是 js 异步特性没有掌握,说明用得少,木有深入了解 js 异步原理,加油呀
@DevinXian 嗯,还是用的少了 :joy
这段代码也可以用的更好
it ('waitBody', async function() {
await driver.sleep(500).wait('body', 30000).html().then(function(code) {
isPageError(code).should.be.false;
})
})
可以先从内部优化
it ('waitBody', async function() {
let getCode = await driver.sleep(500).wait('body', 30000).html();
let code = await getCode;
isPageError(code).should.be.false;
})
最后把 it优化掉,这样就不会回调里面套异步了(这步开始不要照搬,要看你的情况而定来优化it的回调)
let waitBody = new Promise((reslove,reject)=>{
it ('waitBody', function() {
reslove(true)
})
})
(async function () {
await waitBody;
let getCode = await driver.sleep(500).wait('body', 30000).html();
let code = await getCode;
isPageError(code).should.be.false;
})()
如果不希望it自执行,可以再包一层
let waitBodyFunc = function () {
return new Promise((reslove,reject)=>{
it ('waitBody', function() {
reslove(true)
})
})
}
(async function () {
await waitBodyFunc();
let getCode = await driver.sleep(500).wait('body', 30000).html();
let code = await getCode;
isPageError(code).should.be.false;
})()
你可以把最底层的方法都向上包,这样你上层调用,就能像mongose那样愉快了
看返回值是否为Promise对象