Promise详解-1:初识Promise

最近在回顾ES6的知识,想整理下跟Promise相关的内容。我准备整一个Promise解读的系列,看看能深入到什么程度吧。由浅入深,先认识下Promise。

痛苦的回忆:回调地狱

假如现在让你维护一个“古老”的项目,缺少脚手架的加持,只能使用es5的语法来开发,我相信你一定会深刻的体会到es6添加Promise是多么伟大的行为。在es5的时代,异步编程需要依赖回调函数来实现,这就会导致一个问题:回调地狱(callback hell),代码结构会变成复杂,可读性、可维护性差到极致。例如:如果有一个业务需要连续调用三个接口,那么就需要这么写:

ajax('api1', function(res1){
  if(res1.success) {
    ajax('api2', function(res2) {
      if (res2.success) {
        ajax('api3', function(res3){
          if(res3.success) {
            // dosomething....
          }
        });
      }
    })
  }
})

如果场景更复杂的话,可能就会变成这样:

除了接口调用,事件、异步加载等等需要等待的操作基本都需要通过回调来实现。整个项目中充斥着这样的代码基本就只能靠记忆去维护。

Promise是什么?

es6的规范中新增Promise对象,是异步编程的一个解决方案。Promise相当于提供一个容器,这个容器会封装一个单独的“时间线”,这个独立的“时间线”与主线程的执行是并行,当容器内发生变化的时候,容器会更新其状态,外部可以通过API获取到状态变更的结果,并且这个状态会被固定在容器中,保持不变,无论什么时候都可以获取。

Promise对象提供了更清晰的异步操作处理,可以将异步操作封装到Promise内,通过统一的方法来处理异步操作。当包装在Promise中的异步操作有结果时,Promise对象会根据异步操作的结果(正确或是错误)更新状态,并返回结果,我们可以通过Promise的then或者catch方法来获取异步操作的结果。针对上面的多个异步串联的操作,Promise对象提供链式调用的方式,通过then方法将多个异步操作串联起来,形成一个操作序列。这种方式可以避免回调地狱,将多层嵌套变成使得代码更加清晰和易于理解。针对其他多个异步操作的场景,Promise对象还提供了一些静态方法,如Promise.all和Promise.race,用于处理多个异步操作的结果。这些功能使得Promise对象成为处理异步操作的强大工具,能够大大简化异步操作的处理流程,提高代码的可维护性和可读性。

Promise的状态

Promise通过状态来定义包裹的异步操作的目前所处的阶段,Promise提供了三个互斥的状态:fulfilled(已成功) 、rejected(已失败)、pending(进行中),任何Promise对象都处于这三种状态之一。

当我们创建一个Promise对象时,这个Promise对象处于pending状态,再异步操作产生结果后,会有以下两种状态的变化:

  • 异步操作成功:pending转换到fulfilled
  • 异步操作失败:pending转换到rejected

这个状态一旦变更,就不会再改变,而且无论是什么时候都可以获取到对应的结果。就是说在Promise对象的状态发生变化后,在任何时候都可以为Promise添加回调函数都可以会立即得到这个结果。这与事件是完全不同,在事件的模式下,如果你错过了它,就无法在获取结果。

Promise的基础用法

按照ES6的规范,Promise对象内置的Promise构造函数来实例化:

let promise = new Promise(function(resolve, reject) {
    // do sync 
    resolve(); // 将promise的状态置为fulfilled(已成功)
    reject(); // 将promise的状态置为rejected(已失败)
});

这时,我们就得到一个`Promise`对象的实例:`promise`,然后通过这个实例,可以在任何时候取得异步操作的结果:

promise.then(() => {
  // do something
}).catch((error) => {
  console.error(error);
});

通过thencatch两个方法分别捕获Promise对象中包裹的异步操作的结果和错误。

这里需要注意的是,异步操作结束后会通过resolvereject来修改实例的状态。那么这里就不一定是真正反应异步操作的实际结果,而是异步操作想要外界知道的结果。这样说可能有点绕,举个例子,在请求一个接口时,请求是一个异步动作,按照ajax工具思路,应该是根据状态码来修改状态。但是在实际操作中,接口返回200,但是内容是操作失败,虽然这里的接口是请求成功(就http请求而言),但是在业务上是失败的。一般这里也会直接处理成失败的状态而不是成功状态(这就是异步操作真正想要给外界的结果)。

先整个例子

上面是Promise的基础用法,为了更好的说明,这里我先整个例子:现在假设在某个业务系统中,所有接口的请求的返回格式都是:

{
  "errCode": 0,			// 0 成功 1 失败
	"data": [],				// 数据
  "message": ''     // 信息
}

我们通过Promise + XmlHttpRequest简单封装一个ajax方法:

function createUrlParams(data) {
  return Object.keys(data).map((v) => {
    return `${v}=${data[v]}`;
  }).join('&');
}

function ajax(url = '',  data = {}, type = 'GET') {
    return new Promise((resolve, reject) => {
        const xhr = new XMLHttpRequest();
        
        type = type.toUpperCase();

        if (type === 'GET') {
            url += '?' + createUrlParams(data);
            data = null;
        }

        xhr.open(type, url, true);
        
        xhr.onload = function() {
            if (xhr.status >= 200 && xhr.status < 300) {
                let res = JSON.parse(xhr.response);
                if (res.errCode !== 0) {
                    reject({status:'error', result: res});
                } else {
                    resolve({status:'success', result: res})
                }
              } else {
                reject(`请求失败:${xhr.status}`);
              }
        }

        xhr.onerror = function () {
            reject(`请求失败:${xhr.status}`);
        };

        xhr.send(data);
    });
}

上面的ajax方法最终会返回一个Promise实例,在请求完成的时候根据请求的状态和结果修改Promise的状态。例如获取用户的列表可以这么写:

ajax('http://xxxx.com/user/get-list')
.then(res => {
    console.log(res);
}).catch(err => {
    console.error(err);
});

基础方法说明

then方法

上面讲到我们可以通过then方法来获取异步的成功的结果,但其实then方法是接收两个回调方法,如果Promise状态为fulfilled则执行第一个回调方法,失败则执行第二个:

ajax('http://xxxx.com/user/get-list')
  .then(
    () => {
      console.log('success');
  	},
    () => {
      console.log('error');
  	}
  );

不管成功还是失败,then都会返回一个新的promise:

我们先修改下上面的代码,以便更好的观察:

const pAjax = ajax('http://xxxx.com/user/get-list');
const p1 = pAjax.then(
    () => {
      console.log('success');
    },
    () => {
      console.log('error');
    }
);

如果没有特殊操作(这个等会讲),不管成功失败,这个新的promise的状态会被置为fulfilled:

const p2 = p1.then(() => {
    console.log('success 2');
});

从上面的例子可以看出,在then的回调函数中我们并没有返回任何东西,但是then依然会返回一个promise。

例如这样:

const p2 = p1.then()
  	.then(() => {
      console.log('success');
    });

这是then的机制,如果回调函数中没有return的话,则会默认返回一个成功的promise,如果回调函数中有return,则会判断return是否为一个promise,如果不是promise,则会将其包装成promise返回,并且状态为成功。如果是promise,则直接返回,链式调用后面的方法会根据这个promise的状态触发对应的回调函数。

返回非promise

const p1 = pAjax.then(
    () => {
      return {result: 'success'};
    },
    () => {
      return {result: 'error'};
    }
);

const p2 = p1.then((res) => {
    console.log(res);
});

返回promise

可以看到,如果then中返回的是promise,链式后面的函数会等待这个promise的状态变更,再根据promise的状态来执行对应的回调。

状态传递

从上面的例子也可以看到,then主要是受到上一个promise的影响,在pAjax错误的时候,p1会触发错误回调,而p2触发的时候成功的回调。那么如果p1没有捕获错误的话,错误会在p2被捕获到吗?

const p1 = pAjax.then(
    () => {
      console.log('success');
    }
);

const p2 = p1.then(
  () => {
    console.log('success');
  }, 
  () => {
    console.log('error');
  }
)

可以看到,p2捕获到错误,说明错误是会向下传递的。

总结

then函数支持传入两个回调方法,分别为成功的回调和失败的回调,then会根据回调函数的返回值返回一个新的promise,如果返回值不是promise,封装成promise返回,如果是promise则直接返回。如果then没有捕获错误,则会将错误向下传递,这是新的promise的状态为失败。

catch方法

catch方法其实是then(null/undefined, reject())的变相写法,在指定发生错误的时候执行回调函数。

const pAjax = ajax('http://xxxx.com/user/get-list');
const p1 = pAjax.then(() => {
      console.log('success');
    }).catch((err) => {
      console.log(err);
		});

因为catchthen捕获错误的变相写法,所以then具备的特性catch都具备,这里就不多赘述了。

值得一提的是,跟传统的try/catch不一样,在promise中产生的错误,只能在promise的链路上捕获到,不会扩散到外部:

function err() {
    throw new Error('error');
}

try {
	err(); // 抛出错误
  console.log('next'); // 不执行,被错误阻塞
} catch(err) {
  console.log(err); // error对象
}
try {
   promise = ajax('http://xxxx.com/user/get-list'); // 抛出错误
  setTimeout(() => {console.log('next');}, 5000); // 5s后仍执行
} catch(err) {
  console.log(err); // 无法捕获到错误
}

另外,如果在promise中抛出错误,但是没有执行reject方法,promise还是会将状态处理成rejected

function err(){
  return new Promise((resolve, reject) => {
    throw new Error('promise error');
  });
}

err().catch(err => {
  console.log(err);   // Error: promise error
});

但是,如果已经修改了promise的状态,再抛出错误,则是无效的:

function err(){
  return new Promise((resolve, reject) => {
    resolve('success');
    throw new Error('promise error'); // 无效
  });
}

err().then((res) => {
  console.log(res); // success
}).catch(err => {
  console.log(err);   // 无
});

需要注意的,如果已经使用catch捕获了错误,那么错误就不会在向下传递,除非前面的catch将错误重新抛出。

ajax('http://xxxx.com/user/get-list')
	.catch(err => {
      console.log(err); // error信息
  }).catch(err => {
    console.log(err); // undefined
  });
 ajax('http://xxxx.com/user/get-list')
	.catch(err => {
      throw err; // 也可以写成return Promise.reject(err); 
  }).catch(err => {
    console.log(err); // error信息
  });
编写建议

前面讲到,promise的链路上错误是会向下传递的,所以呢,我建议promise的写法是按照需要在指定位置使用 catch捕获错误,不要再then中使用rejected的回调去捕获错误,这样整体的可读性更高:

ajax('http://xxxx.com/user/get-list')
  .then(() => {
    // 步骤1
  })
  .then(() => {
    // 步骤2
  }) // ...
  .catch((err) => {
    console.log(err);
  });

这样看起来更像同步的写法,更清晰可读性更高。

如果是多个promise嵌套调用的话,建议只在最外层捕获错误,这样可以在统一的地方处理错误,埋日志,错误调试等操作都会简化。当然如果不希望中间某些操作的错误终端整个promise,可以在这些操作上添加catch拦截掉错误。

这里假设是一个添加用户的场景,有几个步骤:

  1. 获取录入的用户名(正常是同步的,这里假设是一个promise)
  2. 调用接口校验用户名是否重复
  3. 提交用户名
  4. 刷新用户列表
function getForm()
  	.then(() => {
    }){
  return form();
}

function ApiCheckName(name) {
  return ajax('http://xxxx.com/user/check-name', {name})
    .then(isExists => {
      if (isExists) {
        throw new Error('用户名已存在');
      } else {
        return true;
      }
    })
}

function ApiAddUser(data) {
  return ApiCheckName(data.name)
    .then(() => {
        return ajax('http://xxxx.com/user/add', data, 'POST');
    });
}

function ApiGetUserList() {
  return ajax('http://xxxx.com/user/get-list');
}

// 封装添加用户的方法
function addUser() {
  return getForm()
    .then((form) => {
        return ApiAddUser({name: 'skkk'});
    })
    .then(() => {
      return getUserList();
    });
}

// 外部调用
addUser()
.catch((err) => {
  console.log('失败', err);
})

finally方法

finally方法是在ES2018规范引入的,所以在一些版本较低的浏览器是不支持的。finally方法是不管promise最终是成功还是失败,都会执行该方法。

ajax('http://xxxx.com/user/get-list')
	.then(() => {console.log('success');})
	.catch(() => {console.log('error');})
  .finally(() => {console.log('finally');})

如上面的代码,无论接口请求是否成功,都会执行finally

finally本质上还是then的变种,其实现的效果等于与在then的成功失败回调中分别添加相同的代码:

ajax('http://xxxx.com/user/get-list').finally(() => {
  dosomething();
});

等同于:

ajax('http://xxxx.com/user/get-list').then(
  () => {
    dosomething();
  }, 
  () => {
    dosomething();
  }
)

明显finally更简洁。

then不同的是finally是不接收参数的。

ajax('http://xxxx.com/user/get-list')
	.then(() => { return 1;})
	.catch(() => { return 2; })
  .finally((res) => {console.log(res);})  // undefined

这样我们无法通过传参来判断promise最终的状态,从而进行一些针对的操作。但是还是可以用不过来做一些终结操作。例如:实现一个带进度条的下载功能,不管下载成功或失败都要关闭重置进度条,就可以在finally中实现。

同样的,finally也是返回一个promise

const pAjax = ajax('http://xxxx.com/user/get-list');
const p1 = pAjax.then(() => { return 1;})
	.catch(() => { return 2; });
const p2 = p1.finally(res => {console.log(res);});
const p3 = p2.then(res => {console.log(res);});

可以看到返回值会越过finally传递。

同样,状态也是会向下传递的

const pAjax = ajax('http://xxxx.com/user/get-list');
console.log('pAjax ====>', pAjax);
const p1 = pAjax.finally(res => {console.log(res);});
console.log('p1 ====>', p1);
const p2 = p1.then(
    () => {console.log('success');},
    () => {console.log('error');}
);
console.log('p2 ====>', p2);

除了不接收参数,finally里返回的参数或成功的promise都也不会被传递下去:

const pAjax = ajax('http://localhost:3010');
const p1 = pAjax.finally(() => {
    return 'finally';
});
const p2 = p1.then(
    (res) => {console.log('p2 res', res);},
    (res) => {console.log('p2 res', res);}
);
const p3 = pAjax.finally(() => {
    return Promise.resolve('finally');
});
const p4 = p3.then(
    (res) => {console.log('p4 res', res);},
    (res) => {console.log('p4 res', res);}
);

p2p4都获取到pAjax的结果。

但是如果finally返回了Promise或抛出错误就会向下传递:

const p1 = pAjax.finally(() => {
    throw new Error('finally error');  // 抛出错误
});
const p2 = p1.then(
    (res) => {console.log('p2 res',res);},
    (res) => {console.log('p2 res',res);}
);
const p3 = pAjax.finally(() => {
    throw Promise.reject('finally');  // 返回成功的promise
});
const p4 = p3.then(
    (res) => {console.log('p4 res',res);},
    (res) => {console.log('p4 res',res);}
);

可以看到,无论pAjax是否成功的,但是p2p4都是捕获到p1p3抛出的错误。

当然,实际的开发中千万别这么写,finally就做一些统一的终结操作就行了。如果统一操作也是promise的话,建议单独处理。

Promise.resolve() & Promise.reject()

如果想要返回一个promise,但又不想使用new Promise的方式来实现,就可以使用这两个方法。基本上其功能与字面意义一致,Promise.resolve()会直接返回一个状态为fulfilled的promise,Promise.reject()则返回一个状态为rejected的promise。

Promise.resolve

上面说的是基本功能,不带任何参数会返回一个成功的promise。但是resolve方法可以接受一个参数,其会根据这个参数的不同返回不同的promise。

  1. 传入promise实例

传入promise实例,会直接返回这个实例,不做任何修改。

const p = Promise.resolve(ajax('http://xxxx.com/user/get-list'));
p.then(res => {
    console.log(res);  // {status: 'success', result: {…}}
}); 
  1. 传入thenable对象

thenable对象就是带then方法的对象,像这样的:

{
  then: function(resolve, reject){
    setTimeout(() => {
    	resolve('then');
    }, 500);
  }
}

将这样的对象传给Promise.resolve(),它会将其转换为promise对象,并立刻执行then函数。像这样:

const p = Promise.resolve({
    then(resolve, reject) {
        setTimeout(() => {
            resolve('thenable');
        }, 500);
    }
});
p.then(res => {
    console.log(res);   // thenable
});

then没有resolve或reject,只是一个方法甚至不是一个方法会是什么情况呢?

const p1 = Promise.resolve({
    then() {
        console.log('then function');
        return 'then';
    }
});
p1.then(res => {
    console.log('p1', res); 
});

const p2 = Promise.resolve({
    then: {
        a: 1
    }
});
p2.then(res => {
    console.log('p2', res); 
});

const p3 = Promise.resolve({
    then: '1'
});
p3.then(res => {
    console.log('p3', res); 
});

可以看到,如果then方法没有修改promise的状态的话,then方法会被执行,但是返回的promise会处于pending的状态。而then是非方法的话,会返回一个fulfilled的promise,对象被当做返回值返回。

  1. 其他类型的参数

传入对象、数组、字符串、数字等非方法类的参数,Promise.resolve会立即返回一个fulfilled的promise,并且将参数作为返回值。

Promise.resolve([1,2,3])
	.then(res => {
    console.log(res); // [1,2,3]
  })

传入的参数是一个非promise的方法,会获取该方法的返回值(如果有)做为返回值,同样也是返回一个状态为

fulfilled的promise。

function p1() {
    console.log('function p1'); // function p1
    return 'p1';
}

Promise.resolve(p1())
	.then(res => {
    console.log(res); // p1
  })

function p2() {
    console.log('function p2'); // function p2
}

Promise.resolve(p2())
	.then(res => {
    console.log(res); // undefined
  })

如果在方法中抛出错误呢?会不会走到catch呢?

function p1() {
    throw new Error('p1 error');
}

Promise.resolve(p1())
	.then(res => {
    console.log(res);
  }).catch(err => {
    console.log(err);
  });

答案是啥都没执行,因为p1在执行是就抛出错误了,后续代码终止执行。

Promise.reject

reject无论传不传入都是返回一个状态为rejected的promise。传入的任何参数都会做为失败的理由返回。

// 传入对象
Promise.reject({name: 'reject'})
	.catch(err => {
      console.log('object', err); // object {name: 'reject'}
  });
// 传入字符串
Promise.reject('reject')
	.catch(err => {
      console.log('string', err); // string reject
  });

function p1() {
    console.log('function p1');  // function p1
    return 'p1';
}

// 有返回值的方法
Promise.reject(p1())
	.catch(err => {
      console.log('p1', err); // p1 p1
  });

function p2() {
    console.log('function p2'); // function p2
}

// 无返回值的方法
Promise.reject(p2())
	.catch(err => {
      console.log('p2', err); // p2 undefined
  });

// promise
Promise.reject(ajax('http://xxxx.com/user/get-list'))
	.catch(err => {
      console.log('ajax', err);  // ajax promise
  });

这里跟resolve不一样的是,传入的参数是promise,也会将promise实例理由返回。而不是返回promise实例的结果。

总结

本文介绍了Promise最基础的知识,了解了Promise的基础应用。接下会继续深入了解Promise,敬请期待吧。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/936378.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【蓝桥杯备战】Day 1

1.基础题目 LCR 018.验证回文串 给定一个字符串 s &#xff0c;验证 s 是否是 回文串 &#xff0c;只考虑字母和数字字符&#xff0c;可以忽略字母的大小写。 本题中&#xff0c;将空字符串定义为有效的 回文串 。 示例 1: 输入: s "A man, a plan, a canal: Panama…

让文案生成更具灵活性/chatGPT新功能canvas画布编辑

​ ​ OpenAI最近在2024年12月发布了canvas画布编辑功能&#xff0c;这是一项用途广泛的创新工具&#xff0c;专为需要高效创作文案的用户设计。 无论是职场人士、学生还是创作者&#xff0c;这项功能都能帮助快速生成、优化和编辑文案&#xff0c;提升效率的同时提高内容质量…

使用秘钥登录服务器

在我们测试或生产环境中&#xff0c;为了服务器安全性&#xff0c;有时可能需要以 SSH 密钥的方式登录服务器&#xff0c;接下来&#xff0c;将演示如何通过 SSH 私钥的方式来远程服务器。 一、远程服务器生成密钥对 1、首先在目标远程服务器下生成 SSH 密钥对 ssh-keygen然…

linux-16 关于shell(十五)date,clock,hwclock,man,时间管理,命令帮助

想显示一下当前系统上的时间该怎么显示&#xff1f;有一个命令叫做date&#xff0c;来看date命令&#xff0c;如下图&#xff0c; 第一个星期几对吧&#xff1f;然后是月日小时分钟秒&#xff0c;最后一个是年对吧&#xff1f;CST指的是它的时间格式&#xff0c;我这个可以先姑…

番外篇 | Hyper-YOLO:超图计算与YOLO架构相结合成为目标检测新的SOTA !

前言:Hello大家好,我是小哥谈。Hyper-YOLO,该方法融合了超图计算以捕捉视觉特征之间复杂的高阶关联。传统的YOLO模型虽然功能强大,但其颈部设计存在局限性,限制了跨层特征的融合以及高阶特征关系的利用。Hyper-YOLO在骨干和颈部的联合增强下,成为一个突破性的架构。在COC…

在 Ubuntu 中 make 是否是系统自带的?怎么样查看Linux系统中是否有make?

make 命令 并不是所有 Ubuntu 系统都默认安装的&#xff0c;但它通常是开发工具链的一部分&#xff0c;许多开发者会在安装系统后配置它。make 是一个非常重要的构建工具&#xff0c;用于自动化编译和构建过程&#xff0c;特别是在编译软件或内核时。 make 的来源 make 是一个…

ubuntu+ros新手笔记(一)

系统ubuntu20.04 ros noetic humble(源码安装失败&#xff0c;放弃源码安装了) 1. ubuntu安装vcs 拉取autoware源码的时候需要用到命令 vcs import src < autoware.ai.repos但是ubuntu默认没有安装vcs工具&#xff08;zsh: command not found: vcs&#xff09; 应使用以…

蛋白研究新热点:AI 全方位剖析 DHA 与 Ferrostatin - 1 的作用密码

胰腺癌是一种非常棘手的癌症&#xff0c;传统化疗药物往往对它收效甚微&#xff0c;很难提高患者的生存率。不过&#xff0c;研究人员发现了一种可能的新治疗方向 —— 利用双氢青蒿素&#xff08;DHA&#xff09;诱导癌细胞发生铁死亡。 下面将以Dihydroartemisinin induces …

大数据挖掘建模平台案例分享

大数据挖掘建模平台是由泰迪自主研发&#xff0c;面向企业级用户的大数据挖掘建模平台。平台采用可视化操作方式&#xff0c;通过丰富内置算法&#xff0c;帮助用户快速、一站式地进行数据分析及挖掘建模&#xff0c;可应用于处理海量数据、高复杂性的数据挖掘任务&#xff0c;…

docker安装、升级、以及sudo dockerd --debug查看启动失败的问题

1、docker安装包tar下载地址 Index of linux/static/stable/x86_64/ 2、下载tgz文件并解压 tar -zxvf docker-24.0.8.tgz 解压后docker文件夹下位docker相关文件 3、将老版本docker相关文件&#xff0c;备份 将 /usr/bin/docker下docker相关的文件&#xff0c;mv到备份目录…

远程桌面防护的几种方式及优缺点分析

远程桌面登录是管理服务器最主要的方式&#xff0c;于是很多不法分子打起了远程桌面的歪心思。他们采用暴力破解或撞库的方式破解系统密码&#xff0c;悄悄潜入服务器而管理员不自知。 同时远程桌面服务中的远程代码执行漏洞也严重威胁着服务器的安全&#xff0c;攻击者可以利…

【电子通识】电流倒灌为什么需要注意?

电流倒灌是一个很常见的问题,以“IO电流倒灌”为关键词在百度上进行搜索,可以找到很多相关案例。 电流倒灌问题在5V电平的单片机时代几乎不会发生,主要是因为5V单片的IO耐压值高,单片机内部结构对IO保护设计很好。 到了3.3V单片机时代,这类问题有一定的偶发性,但…

Linux系统编程——进程间通信

目录 一、前言 二、进程间通信的目的 三、进程通信的方法 四、管道 通信 1、进程如何通信 2、管道概念 3、匿名管道 1&#xff09;理解 2&#xff09;匿名管道的创建 3&#xff09;匿名管道用途——控制进程 4&#xff09;匿名管道对多个进程的控制 5&#xff09;总…

【中工开发者】鸿蒙商城实战项目(启动页和引导页)

创建一个空项目 先创建一个新的项目选择第一个&#xff0c;然后点击finish 接下来为项目写一个名字&#xff0c;然后点击finish。 把index页面的代码改成下面代码块的代码&#xff0c;就能产生下面的效果 Entry Component struct Index {build() {Column(){Blank()Column(){…

Hadoop其一,介绍本地模式,伪分布模式和全分布搭建

目录 一、Hadoop介绍 二、HDFS的本地模式 三、伪分布模式 四、Hdfs中的shell命令 五、全分布搭建 六、使用Java代码操作HDFS 1、环境准备 2、单元测试&#xff08;Junit&#xff09;​编辑 一、Hadoop介绍 Hadoop 分为三部分 &#xff1a; Common、HDFS 、Yarn、MapRe…

【Linux-ubuntu通过USB传输程序点亮LED灯】

Linux-ubuntu通过USB传输程序点亮LED灯 一,初始化GPIO配置1.使能时钟2.其他寄存器配置 二&#xff0c;程序编译三&#xff0c;USB传输程序 一,初始化GPIO配置 1.使能时钟 使能就是一个控制信号&#xff0c;用于决定时钟信号是否能够有效的传递或者被使用&#xff0c;就像一个…

django——admin后台管理1

一、admin后台管理 访问url进入&#xff1a; http://127.0.0.1:8000/admin ​ 创建超级管理用户 终端输入以下命令&#xff1a; python manage.py createsuperuser (py36_pingping) E:\django学习\day03-django入门\demo>python manage.py createsuperuser Username: mo…

Jenkins与SonarQube持续集成搭建及坑位详解

Jenkins和SonarQube都是软件开发过程中常用的工具,它们在代码管理、构建、测试和质量管理方面发挥着重要作用。以下是关于Jenkins与SonarQube的作用及整合步骤环境搭建的详细解释: 一、Jenkins与SonarQube的作用 Jenkins: Jenkins是一个开源的持续集成和交付工具,它可以帮…

Docker安装MySQL5.5版本数据库(图文教程)

本章教程,介绍如何使用Docker安装MySQL低版本5.5版本的数据库。 一、拉取镜像 docker pull mysql:5.5二、启动容器 docker run -d --name mysql5.5 --restart=always

Qt实现自定义行编辑器

引言 开发环境项目结构ui界面设计示例代码运行效果总结qt中原有的行编辑器无法满足当前的需要,所以需要自定义行编辑器。 通过上下按键切换到不同的行编辑器,在选中的行编辑器中输入数字,编辑器呈现边框,编辑后按下回车键保存之前编辑的数值,没有按下回车键直接切换上下键…