分享web开发知识

注册/登录|最近发布|今日推荐

主页 IT知识网页技术软件开发前端开发代码编程运营维护技术分享教程案例
当前位置:首页 > 网页技术

callback vs async.js vs promise ?vs async / await

发布时间:2023-09-06 02:10责任编辑:白小东关键词:js

需求:

A、依次读取 A|B|C 三个文件,如果有失败,则立即终止。
B、同时读取 A|B|C 三个文件,如果有失败,则立即终止。

一、callback


需求A

 ?let read = function (code) { ???if (code) { ???????return true; ???} else { ???????return false; ???}}let readFileA = function (callback) { ???if (read(1)) { ???????return callback(null, "111"); ???} else { ???????return callback("a fail"); ???}}let readFileB = function (callback) { ???if (read(1)) { ???????return callback(null, "222"); ???} else { ???????return callback("b fail"); ???}}let readFileC = function (callback) { ???if (read(1)) { ???????return callback(null, "333"); ???} else { ???????return callback("c fail"); ???}}readFileA(function (err, data) { ???if (err) { ???????console.log("open file " + err); ???????return; ???} ???console.log("读取 a.txt 成功!内容:" + data); ???readFileB(function (err, data) { ???????if (err) { ???????????console.log("open file " + err); ???????????return; ???????} ???????console.log("读取 b.txt 成功!内容:" + data); ???????readFileC(function (err, data) { ???????????if (err) { ???????????????console.log("open file " + err); ???????????????return; ???????????} ???????????console.log("读取 c.txt 成功!内容:" + data); ???????}); ???});});

return:

读取 a.txt 成功!内容:111读取 b.txt 成功!内容:222读取 c.txt 成功!内容:333

需求B:太恶心了,不写了,总之很繁琐.

二、async.js


async.js库的详细介绍可以见:[待写]

需求A

async.series

var async = require("async");let read = function (code) { ???if (code) { ???????return true; ???} else { ???????return false; ???}}let readFileA = function (callback) { ???if (read(1)) { ???????return callback(null, "111"); ???} else { ???????return callback("a fail"); ???}}let readFileB = function (callback) { ???if (read(0)) { ???????return callback(null, "222"); ???} else { ???????return callback("b fail"); ???}}let readFileC = function (callback) { ???if (read(1)) { ???????return callback(null, "333"); ???} else { ???????return callback("c fail"); ???}}async.series([readFileA, readFileB, readFileC], ???function (err, datas) { ???????if (err) { ???????????console.log("open file " + err); ???????} ???????console.log(datas); ???????return; ???});

当第二个readFileB()读取失败的话:

return:

open file b fail[ ‘111‘, undefined ]

需求B

async.parallel

var async = require("async");let read = function (code) { ???if (code) { ???????return true; ???} else { ???????return false; ???}}let readFileA = function (callback) { ???if (read(1)) { ???????return callback(null, "111"); ???} else { ???????return callback("a fail"); ???}}let readFileB = function (callback) { ???setTimeout(() => { ???????if (read(0)) { ???????????return callback(null, "222"); ???????} else { ???????????return callback("b fail"); ???????} ???}, 1000);}let readFileC = function (callback) { ???if (read(1)) { ???????return callback(null, "333"); ???} else { ???????return callback("c fail"); ???}}async.parallel([readFileA, readFileB, readFileC], ???function (err, datas) { ???????if (err) { ???????????console.log("open file " + err); ???????} ???????console.log(datas); ???????return; ???});

当第二个readFileB()读取失败 (注意我给它加了setTimeout,为了体现跟上面串行结果的不一样) 的话:

return:

open file b fail[ ‘111‘, undefined, ‘333‘ ]

总结:async.js跟callback比的好处:

1、代码量少了,解决了回调地狱金字塔的缺陷

2、async的第二个参数回调函数里,可以统一处理错误(建议用不同的Error类作区分)

3、成功返回的结果datas可以汇总到一个数组中方便处理

三、promise


[拓展]

promise 知识

new Promise()


// ?promise在new的时候已经开始运行 new Promise(() => console.log("I have already started!"));

return:

I have already started!

promise.then(successCallback, failureCallback);


new Promise((resolve, reject) => resolve()).then(function (data) { ???console.log("success");}, function (data) { ???console.log("fail");})

return:

success

promise.catch(failureCallback)


// promise.catch(failureCallback) 是 promise.then(null, failureCallback) 的缩略形式new Promise((resolve, reject) => reject()).catch( function (data) { ???console.log("fail");})

return:

fail

链式调用


// 链式调用的原理:then函数会返回一个新的promisenew Promise((resolve, reject) => reject()).then(function (data) { ???console.log("success_1");}, function (err) { ???console.log("fail_1");}).then(function (data) { ???console.log("success_2");}, function (err) { ???console.log("fail_2");});

return:

fail_1success_2

提问

问1:then函数会返回一个新的promise,但是then的successCallback和failureCallback这两个回调函数里都没法调用resolve()和reject(),那这个新的promise如何指定最终状态呢?

then的successCallback和failureCallback里等同于
不返回resolve(undefined)
return 1resolve(1)
return Promise.resolve()resolve()
return Promise.reject()reject()
throw Error()reject()
return new Promise()以此类推

而普通的 promise 对象,如果不显示调用 resolve/reject ,则没有任何反应,例如:

new Promise((resolve, reject) => {return 1;}).then(function (data) { ???console.log("success");}, function (err) { ???console.log("fail");});

return:

没有任何输出

问2:then函数如果successCallbackfailureCallback都为null,会发生什么?

什么都不会发生,.then(null, null)只要一方为null,等于交给下一个then去接管这个回调

new Promise((resolve, reject) => reject()) ???.then(null, null) ???.then(null, null) ???.then(null, null) ???.then(null, null) ???.then(function (data) { ???????console.log("success_2"); ???}, function (err) { ???????console.log("fail_2"); ???});

所以按照上面 2 个提问揭示的规律,我们可以写成下面优雅的代码

// 链式调用的原理:then函数会返回一个新的promisenew Promise((resolve, reject) => resolve()).then((data) => { ???console.log("success_1");}).then((data) => { ???console.log("success_2"); ???throw Error("error");}).then((data) => { ???console.log("success_3");}).catch((err) => { ???console.log(err);}); 

return:

success_1success_2Error: error ……

注:.catch()后还可以继续接.then().catch()

这就达到了如下别人家同步代码的清晰的表达s:

try { ???let result = syncDoSomething(); ???let newResult = syncDoSomethingElse(result); ???let finalResult = syncDoThirdThing(newResult); ???console.log(`Got the final result: ${finalResult}`); ?} catch(error) { ???console.log(error);}

所以,需求A:

let read = function (code) { ???if (code) { ???????return true; ???} else { ???????return false; ???}}let readFileA = function () { ???return new Promise(function (resolve, reject) { ???????if (read(1)) { ???????????resolve("111"); ???????} else { ???????????reject("a fail"); ???????} ???});}let readFileB = function () { ???return new Promise(function (resolve, reject) { ???????if (read(1)) { ???????????resolve("222"); ???????} else { ???????????reject("b fail"); ???????} ???});}let readFileC = function () { ???return new Promise(function (resolve, reject) { ???????if (read(1)) { ???????????resolve("333"); ???????} else { ???????????reject("c fail"); ???????} ???});}//[串行] 场景:依次预加载多个资源,如果中途有失败,则进入.catch()readFileA().then(function (data) { ???console.log("读取 a.txt 成功!内容:" + data); ???return readFileB();}).then(function (data) { ???console.log("读取 b.txt 成功!内容:" + data); ???return readFileC();}).then(function (data) { ???console.log("读取 c.txt 成功!内容:" + data); ???return "读取结束";}).then(function (data) { ???console.log(data); ???return;}).catch(function (err) { ???console.log("open file " + err);})

[拓展]

promise vs 事件监听

1\事件对于同一对象上发生多次的事情(如 keyup、touchstart 等)

通过 .then 形式添加的回调函数,甚至都在异步操作完成之后才被添加的函数,都会被调用,如上所示。

2\如果 promise 已成功或失败,且您之后添加了成功/失败回调,则将会调用正确的回调,即使事件发生在先。
3\对某些功能可用的准确时间不是那么关注,更多地是关注对结果作出的反应。
4\甚至都在异步操作完成之后才被添加的函数,都会被调用


promise 扩展知识

Promise.resolve()Promise.reject()


手动创建一个已经resolve或者reject的promise的快捷方法。

promise.all:同时实现了需求B:


//promise.all [并行] 场景:预加载多个资源,都完成后才能进入页面Promise.all([readFileA(), readFileB(), readFileC()]).then(function (datas) { ???console.log(datas); //所有promise都resolve,返回array ???return;}).catch(function (err) { ???console.log("open file " + err); //只要有一个promise是reject,返回这个reject的value})

promise.race


//promise.race [并行] 场景:taskA:fetch图片,taskB:settimeout抛错,让两个task赛跑实现请求超时报错功能Promise.race([taskA(), taskB()]).then(function (data) { //进到resolve还是reject回调只取决于第一个确定状态的Promise ???console.log(data); ???return;}).catch(function (err) { ???console.log("读取图片超时");})

总结:promise跟callback比的好处:

1、代码量少了,解决了回调地狱金字塔的缺陷

2、.catch可以统一处理错误(建议用不同的Error类作区分)

四、async / await

需求A:

let read = function (code) { ???if (code) { ???????return true; ???} else { ???????return false; ???}}let readFileA = function () { ???return new Promise(function (resolve, reject) { ???????if (read(1)) { ???????????resolve("111"); ???????} else { ???????????reject("a fail"); ???????} ???});}let readFileB = function () { ???return new Promise(function (resolve, reject) { ???????if (read(1)) { ???????????resolve("222"); ???????} else { ???????????reject("b fail"); ???????} ???});}let readFileC = function () { ???return new Promise(function (resolve, reject) { ???????if (read(1)) { ???????????resolve("333"); ???????} else { ???????????reject("c fail"); ???????} ???});}async function test() { ???try { ???????let re_a = await readFileA(); ???????let re_b = await readFileB(); ???????let re_c = await readFileC(); ???????console.log({re_a, re_b, re_c}); //如果都成功,return: { re_a: ‘111‘, re_b: ‘222‘, re_c: ‘333‘ } ???} catch (err) { ???????console.log(err); // 如果b失败,return: b fail ???}}test(); 

总结:async / await 跟 callback 比的好处:

1、代码量最少,解决了回调地狱金字塔的缺陷(Promise 通过 then 链来解决callback多层回调金字塔的问题,现在又用 async/await 来进一步优化它)(基于promise的async / await也试图淘汰promise)

2、.catch可以统一处理错误(建议用不同的Error类作区分)


[拓展]

1、async 函数就是 Generator 函数的语法糖,本质上并不是同步代码

2、async 用于申明一个 function 是异步的,而 await (async wait) 用于等待一个异步方法执行完成。

3、await 只能出现在 async 函数中,所以在代码的顶层,我们无法使用await,所以添加它.then/catch来处理最终结果或掉落错误是正常的做法。

try { ???????let re_a = await readFileA(); ???????let re_b = await readFileB(); ???????let re_c = await readFileC(); ???????console.log({re_a, re_b, re_c}); ???} catch (err) { ???????console.log(err); ???}

return:

报错

或者顶层使用立即执行函数表达式(IIFE)

(async () => { ???try { ???????let re_a = await readFileA(); ???????let re_b = await readFileB(); ???????let re_c = await readFileC(); ???????console.log({re_a, re_b, re_c}); ???} catch (err) { ???????console.log(err); ???} })()

return:

{ re_a: ‘111‘, re_b: ‘222‘, re_c: ‘333‘ }

return:

TypeError: (intermediate value)(...) is not a function

上面的例子还可以这样写:

async function test() { ???try { ???????let re_a = await readFileA(); ???????let re_b = await readFileB(); ???????let re_c = await readFileC(); ???????console.log({re_a, re_b, re_c}); //如果都成功,return: { re_a: ‘111‘, re_b: ‘222‘, re_c: ‘333‘ } ???} catch (err) { ???????console.log(err); // 如果b失败,return: b fail ???}}test().then(function(data){ ???console.log("success");},function(err){ ???console.log("fail"); }); 

return:

{ re_a: ‘111‘, re_b: ‘222‘, re_c: ‘333‘ }success

4、实际上 async 申明的 function 返回的就是一个 Promise 对象,这就是 await 必须用在 async 函数中的原因。async 函数调用不会造成阻塞,它内部所有的阻塞都被封装在一个 Promise 对象中异步执行。

区别是,async 申明的 function 里可以通过 return值 / 抛异常 来实现普通 Promise 的 resolve() / reject()

下面是对等关系:

// async函数async function foo () { ?return ‘a‘}// Promisefunction foo () { ?return Promise.resolve(‘a‘)}
// async函数async function foo () { ?throw new Error(‘error‘)}// Promisefunction foo () { ?return Promise.reject(new Error(‘error‘))}

promise.all实现需求B

async/await 同样适用于 Promise.all,因为 Promise.all 本身返回的就是 promise 对象。

let read = function (code) { ???if (code) { ???????return true; ???} else { ???????return false; ???}}let readFileA = function () { ???return new Promise(function (resolve, reject) { ???????if (read(1)) { ???????????resolve("111"); ???????} else { ???????????reject("a fail"); ???????} ???});}let readFileB = function () { ???return new Promise(function (resolve, reject) { ???????if (read(1)) { ???????????resolve("222"); ???????} else { ???????????reject("b fail"); ???????} ???});}let readFileC = function () { ???return new Promise(function (resolve, reject) { ???????if (read(1)) { ???????????resolve("333"); ???????} else { ???????????reject("c fail"); ???????} ???});}async function test() { ???try { ???????let re_a = await readFileA(); ???????let re_b = await readFileB(); ???????let re_c = await readFileC(); ???????console.log({re_a, re_b, re_c}); ???} catch (err) { ???????console.log(err); ???}}async function test() { ???try { ????????let results = await Promise.all([ ???????????readFileA(), ???????????readFileB(), ???????????readFileC(), ???????????]); ???????console.log(results); ???} catch (err) { ???????console.log(err); ???}}test();

#### 参考资料

[使用 promises]
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Using_promises

[理解 JavaScript 的 async/await]
https://segmentfault.com/a/1190000007535316

[javascript.info-Async/await]
https://javascript.info/async-await#async-functions

callback vs async.js vs promise ?vs async / await

原文地址:https://www.cnblogs.com/xjnotxj/p/9477987.html

知识推荐

我的编程学习网——分享web前端后端开发技术知识。 垃圾信息处理邮箱 tousu563@163.com 网站地图
icp备案号 闽ICP备2023006418号-8 不良信息举报平台 互联网安全管理备案 Copyright 2023 www.wodecom.cn All Rights Reserved