JavaScript回调函数的高手指南

2023-01-16 0 570

全文:责任编辑Sonbhadra说明反弹表达式的基本概念,与此同时帮你界定三种反弹:并行和触发器。

反弹表达式是每一后端开发人员都如果晓得的基本概念众所周知。反弹可用作字符串、计时表达式、promise、阿提斯鲁夫尔谷中。

责任编辑Sonbhadra说明反弹表达式的基本概念,同时帮你界定三种反弹:并行和触发器。

1.反弹表达式

具体来说写两个向人寒暄的表达式。

只须要建立两个拒绝接受 name 模块的表达式 greet(name)。那个表达式应回到寒暄的最新消息:

function greet(name) { return `Hello, ${name}!`; } greet(Cristina); // => Hello, Cristina!

假如向许多人寒暄该咋办?能用特定的字符串方式 array.map() 能同时实现:

const persons = [Cristina, Ana]; const messages = persons.map(greet); messages; // => [Hello, Cristina!, Hello, Ana!]

ons 字符串的大部份原素,并依次用每一原素做为初始化模块来初始化 greet() 表达式:`greet(Cristina), greet(Ana)。

有趣的是 persons.map(greet) 方式能接受 greet() 表达式做为模块。这种 greet() 就成了反弹表达式。

persons.map(greet) 是用另两个表达式做为模块的表达式,因而被称作低阶表达式。

反弹表达式做为低阶表达式的模块,低阶表达式透过初始化反弹表达式来继续执行操作方式。关键的是低阶表达式负责管理初始化反弹,并为其提供更多恰当的模块。

在后面的范例中,低阶表达式 persons.map(greet) 负责管理初始化 greet() 表达式,并依次把字符串中大部份的原素 Cristina 和 Ana 做为模块。这就为辨识反弹提供更多了两条单纯的准则。假如你表述了两个表达式,并将其作模块提供更多给另两个表达式不然,所以这就建立了两个反弹。

你能他们撰写采用反弹的低阶表达式。上面是 array.map() 方式的差值版:

function map(array, callback) { const mappedArray = []; for (const item of array) { mappedArray.push( callback(item) ); } return mappedArray; } function greet(name) { return `Hello, ${name}!`; } const persons = [Cristina, Ana]; const messages = map(persons, greet);messages; // => [Hello, Cristina!, Hello, Ana!]

map(array, callback) 是两个低阶表达式,因为它用反弹表达式做为模块,然后在其主体内部初始化该反弹表达式:callback(item)。

注意,常规表达式(用关键字 function 表述)或箭头表达式(用粗箭头 => 表述)同样能做为反弹采用。

2.并行反弹

反弹的初始化方式有三种:并行和触发器反弹。

并行反弹是“阻塞”的:低阶表达式直到反弹函数完成后才继续继续执行。

例如,初始化 map() 和 greet() 表达式。

function map(array, callback) { console.log(map() starts); const mappedArray = []; for (const item of array) { mappedArray.push(callback(item)) } console.log(map() completed); return mappedArray; } function greet(name) { console.log(greet() called); return `Hello, ${name}!`; } const persons = [Cristina]; map(persons, greet); // logs map() starts // logs greet() called // logs map() completed

其中 greet() 是并行反弹。

并行反弹的步骤:

低阶表达式开始继续执行:map() starts反弹表达式继续执行:greet() called最后低阶表达式完成它他们的继续执行过程:map() completed

并行反弹的范例

许多原生 JavaScript 类型的方式都采用并行反弹。

最常用的是 array 的方式,例如: array.map(callback), array.forEach(callback), array.find(callback), array.filter(callback), array.reduce(callback, init)

// Examples of synchronous callbacks on arrays const persons = [Ana, Elena]; persons.forEach( function callback(name) { console.log(name); } ); // logs Ana // logs Elena const nameStartingA = persons.find( function callback(name) { return name[0].toLowerCase() === a; } ); nameStartingA; // => Ana const countStartingA = persons.reduce( function callback(count, name) { const startsA = name[0].toLowerCase() === a; return startsA ? count + 1 : count; }, 0 ); countStartingA; // => 1

字符串类型的 string.replace(callback) 方式也能拒绝接受并行继续执行的反弹:

// Examples of synchronous callbacks on strings const person = Cristina; // Replace i with 1 person.replace(/./g, function(char) { return char.toLowerCase() === i ? 1 : char; } ); // => Cr1st1na

3.触发器反弹

触发器反弹是“非阻塞的”:低阶表达式无需等待反弹完成即可完成其继续执行。低阶表达式可确保稍后在特定事件上继续执行反弹。

在以下的范例中,later() 表达式的继续执行延迟了 2 秒:

console.log(setTimeout() starts); setTimeout(function later() { console.log(later() called); }, 2000); console.log(setTimeout() completed); // logs setTimeout() starts // logs setTimeout() completed // logs later() called (after 2 seconds)

later() 是两个触发器反弹,因为 setTimeout(later,2000) 启动并完成了继续执行,但是 later() 在 2 秒后继续执行。

触发器初始化反弹的步骤:

低阶表达式开始继续执行:setTimeout()starts低阶表达式完成其继续执行: setTimeout() completed反弹表达式在 2 秒钟后继续执行: later() called

触发器反弹的范例

计时表达式触发器初始化反弹:

setTimeout(function later() { console.log(2 seconds have passed!); }, 2000); // After 2 seconds logs 2 seconds have passed! setInterval(function repeat() { console.log(Every 2 seconds); }, 2000); // Each 2 seconds logs Every 2 seconds!

DOM 事件侦听器还触发器初始化阿提斯鲁夫尔谷表达式(反弹表达式的子类型):

const myButton = document.getElementById(myButton); myButton.addEventListener(click, function handler() { console.log(Button clicked!); }); // Logs Button clicked! when the button is clicked

4.触发器反弹表达式与触发器表达式

在表达式表述之前加上特定关键字 async 会建立两个触发器表达式:

async function fetchUserNames() { const resp = await fetch(https://api.github.com/users?per_page=5); const users = await resp.json(); const names = users.map(({ login }) => login); console.log(names); }

fetchUserNames() 是触发器的,因为它以 async 为前缀。表达式 await fetch(https://api.github.com/users?per_page=5son()。

触发器表达式是 promise 之上的语法糖。当遇到表达式 await <promise> (初始化 fetch() 会回到两个promise)时,触发器表达式会暂停继续执行,直到 promise 被解决。

触发器反弹表达式和触发器表达式是不同的两个术语。

触发器反弹表达式由低阶表达式以非阻塞方式继续执行。但是触发器表达式在等待 promise(await <promise>)解析时会暂停继续执行。

但是你能把触发器表达式用作触发器回调!

让我们把触发器表达式 fetch UserNames() 设为触发器反弹,只需单击按钮即可初始化:

const button = document.getElementById(fetchUsersButton); button.addEventListener(click, fetchUserNames);

总结

反弹是两个能做为模块传给另两个表达式(低阶表达式)继续执行的表达式。

反弹表达式有三种:并行和触发器。

并行反弹是阻塞的,触发器反弹是非阻塞的。

最后考考你:setTimeout(callback,0) 继续执行 callback 时是并行还是触发器的?

责任编辑转自segmentfault:疯狂的技术宅,转载请先联系作者授权

原文链接:https://segmentfault.com/a/1190000038869766

点击关注,第一时间了解华为云新鲜技术~

相关文章

发表评论
暂无评论
官方客服团队

为您解决烦忧 - 24小时在线 专业服务