JS基础 Promise
Posted wgchen~
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JS基础 Promise相关的知识,希望对你有一定的参考价值。
阅读目录
Promise
javascript 中存在很多异步操作,Promise 将异步操作队列化,按照期望的顺序执行,返回符合预期的结果。可以通过链式调用多个 Promise 达到我们的目的。
Promise 在各种开源库中已经实现,现在标准化后被浏览器默认支持。
Promise 是一个拥有 then 方法的对象或函数。
问题探讨
下面通过多个示例来感受一下不使用 promise 时,处理相应问题的不易,及生成了不便阅读的代码。
定时嵌套
下面是一个定时器执行结束后,执行另一个定时器,这种嵌套造成代码不易阅读
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>wgchen</title>
</head>
<style>
div
width: 100px;
height: 100px;
background: yellowgreen;
position: absolute;
</style>
<body>
<div></div>
</body>
<script>
function interval(callback, delay = 100)
let id = setInterval(() => callback(id), delay);
const div = document.querySelector("div");
interval(timeId =>
const left = parseInt(window.getComputedStyle(div).left);
div.style.left = left + 10 + "px";
if (left > 200)
clearInterval(timeId);
interval(timeId =>
const width = parseInt(window.getComputedStyle(div).width);
div.style.width = width - 1 + "px";
if (width <= 0) clearInterval(timeId);
, 10);
, 100);
</script>
</html>
图片加载
下面是图片后设置图片边框,也需要使用回调函数处理,代码嵌套较复杂
function loadImage(file, resolve, reject)
const image = new Image();
image.src = file;
image.onload = () =>
resolve(image);
;
image.onerror = () =>
reject(new Error("load fail"));
;
document.body.appendChild(image);
loadImage(
"888.png",
image =>
image.style.border = "solid 5px red";
,
error =>
console.log(error);
);
加载文件
下面是异步加载外部JS文件,需要使用回调函数执行,并设置的错误处理的回调函数
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>wgchen</title>
<link rel="shortcut icon" href="#"/>
</head>
<body>
</body>
<script>
function load(file, resolve, reject)
const script = document.createElement("script");
script.src = file;
script.onload = resolve;
script.onerror = reject;
document.body.appendChild(script);
load(
"hd.js",
script =>
console.log(`$script.path[0].src 加载成功`);
hd();
,
error =>
console.log(`$error.srcElement.src 加载失败`);
);
</script>
</html>
hd.js
function hd()
console.log("hd function run");
如果要加载多个脚本时需要嵌套使用,下面 wgchen.js 依赖 hd.js,需要先加载 hd.js 后加载wgchen.js
不断的回调函数操作将产生回调地狱,使代码很难维护
wgchen.js
function wgchen()
console.log("wgchen function run");
hd();
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>wgchen</title>
<link rel="shortcut icon" href="#"/>
</head>
<body>
</body>
<script>
function load(file, resolve, reject)
const script = document.createElement("script");
script.src = file;
script.onload = resolve;
script.onerror = reject;
document.body.appendChild(script);
load(
"hd.js",
script =>
load(
"wgchen.js",
script =>
wgchen();
,
error =>
console.log(`$error.srcElement.src 加载失败`);
);
,
error =>
console.log(`$error.srcElement.src 加载失败`);
);
</script>
</html>
异步请求
使用传统的异步请求也会产生回调嵌套的问题,下在是获取wgchen的成绩,需要经过以下两步
1、根据用户名取得 wgchen 的编号
2、根据编号获取成绩
启动php服务
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>wgchen</title>
<link rel="shortcut icon" href="#"/>
</head>
<body>
</body>
<script>
function ajax(url, resolve, reject)
let xhr = new XMLHttpRequest();
xhr.open("GET", url);
xhr.send();
xhr.onload = function()
if (this.status == 200)
resolve(JSON.parse(this.response));
else
reject(this);
;
ajax("http://tt.cc/testData/user.php?name=wgchen", user =>
// console.log(user.id);
ajax(
`http://tt.cc/testData/wgchen.php?id=$user["id"]`,
response =>
console.log(response);
);
);
</script>
</html>
user.php
<?php
$user = [
'name'=>$_GET['name'],
'file'=>'user.php',
'id'=>18
];
echo json_encode($user);
wgchen.php
<?php
$user = [
'name'=>'wgchen',
'file'=>'wgchen.php',
'id'=>$_GET['id']
];
echo json_encode($user);
肯德基
下面是模拟肯德基吃饭的事情,使用 promise 操作异步的方式每个阶段会很清楚
let kfc = new Promise((resolve, reject) =>
console.log("肯德基厨房开始做饭");
resolve("我是肯德基,你的餐已经做好了");
);
let dad = kfc.then(msg =>
console.log(`收到肯德基消息: $msg`);
return
then(resolve)
setTimeout(() =>
resolve("孩子,我吃了两秒了,不辣,你可以吃了");
, 2000);
;
);
let son = dad.then(msg =>
return new Promise((resolve, reject) =>
console.log(`收到爸爸消息: $msg`);
setTimeout(() =>
resolve("妈妈,我和wgchen爸爸吃完饭了");
, 2000);
);
);
let ma = son.then(msg =>
console.log(`收到孩子消息: $msg,事情结束`);
);
而使用以往的回调方式,就会让人苦不堪言
function notice(msg, then)
then(msg);
function meal()
notice("肯德基厨房开始做饭", msg =>
console.log(msg);
notice("我是肯德基,你的餐已经做好", msg =>
console.log(`收到肯德基消息: $msg`);
setTimeout(() =>
notice("孩子,我吃了两秒了,不辣,你可以吃了", msg =>
console.log(`收到爸爸消息: $msg`);
setTimeout(() =>
notice("妈妈,我和wgchen吃完饭了", msg =>
console.log(`收到孩子消息: $msg,事情结束`);
);
, 2000);
);
, 2000);
);
);
meal();
异步状态
Promise 可以理解为承诺,就像我们去KFC点餐服务员给我们领取餐票,这就是承诺。如果餐做好了叫我们这就是成功,如果没有办法给我们做出食物这就是拒绝。
- 一个 promise 必须有一个 then 方法用于处理状态改变
状态说明
Promise 包含 pending、fulfilled、rejected 三种状态
- pending 指初始等待状态,初始化 promise 时的状态
- resolve 指已经解决,将 promise 状态设置为 fulfilled
- reject 指拒绝处理,将 promise 状态设置为 rejected
- promise 是生产者,通过 resolve 与 reject 函数告之结果
- promise 非常适合需要一定执行时间的异步任务
- 状态一旦改变将不可更改
promise 是队列状态,就像体育中的接力赛,或多米诺骨牌游戏,状态一直向后传递,当然其中的任何一个promise也可以改变状态。
promise 没有使用 resolve 或 reject 更改状态时,状态为 pending
console.log(
new Promise((resolve, reject) => )
);
当更改状态后
console.log(
new Promise((resolve, reject) =>
resolve("fulfilled");
)
);
console.log(
new Promise((resolve, reject) =>
reject("rejected");
)
);
promise 创建时即立即执行即同步任务,then 会放在异步微任务中执行,需要等同步任务执行后才执行。
let promise = new Promise((resolve, reject) =>
resolve("fulfilled");
console.log("wgchen");
);
promise.then(msg =>
console.log(msg);
);
console.log("wgchen.blog.csdn.net");
- promise 的 then、catch、finally的方法都是异步任务
- 程序需要将主任务执行完成才会执行异步队列任务
const promise = new Promise(resolve => resolve("success"));
promise.then(alert);
alert("wgchen.blog.csdn.net");
promise.then(() =>
alert("wgchen");
);
Promise 状态设置为 fulfilled ,然后执行 then 方法
下例在三秒后将 Promise 状态设置为 fulfilled ,然后执行 then 方法
new Promise((resolve, reject) =>
setTimeout(() =>
resolve("fulfilled");
, 3000);
).then(
msg =>
console.log(msg);
,
error =>
console.log(error);
);
状态被改变后就不能再修改了,下面先通过 resolve 改变为成功状态,表示 promise 状态已经完成,就不能使用 reject 更改状态了
new Promise((resolve, reject) =>
resolve("操作成功");
reject(new Error("请求失败"));
).then(
msg =>
console.log(msg);
,
error =>
console.log(error);
);
动态改变
下例中 p2 返回了 p1 所以此时 p2 的状态已经无意义了,后面的 then 是对 p1 状态的处理。
以上是关于JS基础 Promise的主要内容,如果未能解决你的问题,请参考以下文章