备赛蓝桥杯之第十五届职业院校组省赛第三题:产品360度展示
提示:本篇文章仅仅是作者自己目前在备赛蓝桥杯中,自己学习与刷题的学习笔记,写的不好,欢迎大家批评与建议
由于个别题目代码量与题目量偏大,请大家自己去蓝桥杯官网【连接高校和企业 - 蓝桥云课】去寻找原题,在这里只提供部分原题代码
本题目为:2024年十五届省赛职业院校组真题第三题:产品360度展示
题目:
需要考生作答的代码段如下:
/**
* @param {*} initialValue 初始值
* @param {Array} sequence 由普通函数或 Promise 函数组成的数组
* @return {Promise}
*/
const pipeline = (initialValue, sequence) => {
// TODO: 待补充代码
};
题目要求:
请在 `js/utils.js` 文件中的 TODO 部分,实现以下目标:
封装一个支持异步的 `pipeline` 管道函数,能够按顺序执行一系列异步操作,每个异步操作的结果将作为下一个异步操作的输入。
答案:
const pipeline = (initialValue, sequence) => {
// TODO: 待补充代码
return sequence.reduce(async (x, f) => f(await x), initialValue)
};
拓展学习
组合与管道
reduce方法
累加器与当前值的类似操作`(x,y)=>y(x),初始值`
前言
我们假设一种需求,即“让一个数字,先进行+1,再进行*3”
通常我们普遍来说会像这样来实现这个效果
// value (1+1)*3 //6
function add1(x){
return x + 1;
}
function mul3(x){
return x * 3;
}
console.log(mul3(add1(1))) //6
这样写,我们可以实现上述操作
但是如果有很多的步骤,那么我们会发现后续调用的方法会非常多非常麻烦
所以我们就引入了一个方法组合(compose)
组合
像上述假设,我们再使用组合的方法来实现
function add1(x){
return x + 1;
}
function mul3(x){
return x * 3;
}
function compose (f,g){
return function (x){
return f(g(x))
}
}
console.log(compose(mul3,add1)(1)) //6
注意compose组合是从右向左去执行,因此在上述定义代码中
compose (f,g)
先去执行函数g再去执行函数f,即f(g(x))
在运用代码中
compose(mul3,add1)
先去执行add1再去执行mul3
当产生更多的操作时,我们可以使用递归与迭代的方法来定义compose
递归
当有[funs[0],funs[1],funs[3]]时
将funs[3]输出结果传递给funs[1]再将结果传递给funs[0]
定义代码如下
function add1(x){
return x + 1;
}
function mul3(x){
return x * 3;
}
function compose(...funs){
let count = funs.length -1;
let result = undefined;
return function fn(x){
if(count < 0){
return result;
}
result = funs[count--](x)
return fn(result)
}
}
console.log(compose(mul3,add1)(1)) //6
迭代
当有[funs[0],funs[1],funs[3]]时
相比递归来说,迭代的方法,就是把funs[3]->funs[1]->funs[0]三个方法,初步灌进去
定义代码如下
function add1(x){
return x + 1;
}
function mul3(x){
return x * 3;
}
function compose(...funs){
let callback = function(f,g){
return function(x){
return f(g(x))
}
}
let fn = function(funs[2](x)){
return funs[0]funs[1](fun[2](x))
}
for(let i=1;i < funs.length; i++){
fn = callback(fn, funs[i])
}
return fn;
}
console.log(compose(mul3, add1)(1)) //6
reduce的实现
reduce的实现就是累加器的功能
function add1(x){
return x + 1;
}
function mul3(x){
return x * 3;
}
function compose(...funs){
if(funs.length === 0){
return arg => arg
}
if(funs.length ===1){ }
return funs.reduce((a,b) => (...args) => a(b(...args)))
}
console.log(compose(mul3, add1)(1)) //6
管道
管道相比组合来说唯一的区别其实就是
组合:从右向左
管道:从左向右
而对于定义代码来说,
就是加上reverse()即可
function add1(x){
return x + 1;
}
function mul3(x){
return x * 3;
}
function pipe(...funs){
if(funs.length === 0){
return arg => arg
}
if(funs.length ===1){ }
return funs.reverse().reduce((a,b) => (...args) => a(b(...args)))
}
//这就变成了'先*3再+1'
console.log(pipe(mul3, add1)(1)) //4
本题作者想说
目标
Pipeline 管道函数
处理一系列的异步操作,并且在处理时,需要按顺序执行,每个任务的结果会作为下一个任务的输入。
思路
观察代码
观察需要修改的代码
在题目中也有相对官方的解释
- `initialValue`:管道的初始值(即 `sequence` 中第一个函数的参数)。它是整个异步管道的起点。第一个异步步骤将以此值开始,并且后续步骤将在前一步骤的输出基础上进行。
- `sequence`:是一个由具有返回值和可以传参的函数组成的数组,函数可以是普通函数也可以是 Promise 函数。每个函数接收前一个步骤的输出(即该函数的参数是上一个函数的执行结果),并返回一个 Promise。这个数组定义了整个管道中的处理步骤和它们的顺序。
- `pipeline` 函数返回一个 `Promise`,这个 `Promise` 最终解析为整个管道执行完成后的结果。
我们自己理解起来呢,即
sequence就是让产品动起来的函数,由于动起来的情况与函数太多,所以sequence就是一个函数数组
initialValue就是整个sequence函数数组的初始值,即初始的产品状态
/**
* @param {*} initialValue 初始值
* @param {Array} sequence 由普通函数或 Promise 函数组成的数组
* @return {Promise}
*/
const pipeline = (initialValue, sequence) => {
// TODO: 待补充代码
};
经过我们的console.log分析,发现
initialValue的值为:
<div class="inner" style="transition: unset; transform: rotateX(-20deg) rotateY(0deg) rotateZ(0deg); background-position: right center;">
<div class="screen" style="transition: unset; transform: rotateX(0deg);">…</div>
<div class="computerbody">…</div>
</div>
sequence的值为:
(5) [ƒ, ƒ, ƒ, ƒ, ƒ]
0: (element) => {…}
1: (element) => {…}
2: (element) => {…}
3: (element) => {…}
4: (element) => {…}
length: 5
[[Prototype]]: Array(0)
这样我们就可以清晰的理解,sequence中的函数来控制initialValue某些具体的值从而实现360度的展示
其次,观察具体的值之后,我们还看到了`const pipeline = (initialValue, sequence) =>`
这就表示我们要最具体的使用pipeline管道函数来处理这个事件
分析逻辑
Pipeline 管道函数:Pipeline 管道函数是一种用于数据处理和转换的编程模式,它将一系列的处理步骤串联起来,使得数据可以在这些步骤之间流动和转换。
我们首先知道了具体的函数操作,那么我们就要使其每个函数都被执行,可以理解为将数组中的每个函数都遍历一遍
这样我们就用到了reduce方法:reduce方法对数组中的每个元素执行一个由您提供的reducer函数(升序执行),将其结果汇总为单个返回值。
将每个sequence中的方法进行遍历
sequence.reduce()
内部的处理,首先我们要定义两个值
一个为累加器,将当前被执行的函数进行保存与执行:x
一个当前的值(当前执行的方法),说明当前正在用的是sequence中的哪个方法:f
(x, f) =>
之后我们将当前的x作为函数去执行当前的方法f,
在后面会说明,因为每次调用之后,都会有一个函数,重新初始化这个x值,因此传入x值无关紧要
f(x)
之后定义异步函数,因为该操作一定要是异步的,即当await后的函数执行过后,再次执行async的函数
这里就是当x传入之后再执行下一次sequence中的函数,即:
async (x, f) => f(await x)
最后题目要求中提到`第一个异步步骤将以此值开始,并且后续步骤将在前一步骤的输出基础上进行。`
说明每一个方法的执行都要使initialValue作为初始值,因此再次定义一个初始值,即:
, initialValue
最后将代码返回出去即可
return
设计代码
return sequence.reduce(async (x, f) => f(await x), initialValue)
注意
Pipeline 管道函数
reduce方法
累加器与当前值的类似操作`(x,y)=>y(x),初始值`
感谢观看此篇文章,谢谢大家的支持,本片文章只是我自己学习的历程,有些写的不好地方欢迎大家交流改动。
长路漫漫,我们还需努力!