回调函数、Promise、Generator 函数和async函数

回调函数

<script>
  function getFile(url, myCallback) {
    let req = new XMLHttpRequest();
    req.open("GET", url);
    req.onload = function () {
      if (req.status == 200) {
        myCallback(req.responseText);
      } else {
        myCallback("Error: " + req.status);
      }
    };
    req.send();
  }
  //错误url 404
  getFile("../for-test.html", (res) => {
    console.log(res); //Error: 404
  });
  //正确url
  getFile("../../for-test.html", (res) => {
    console.log(res); //test
  });
</script>

多重请求导致的 回调地狱

<script>
  function getFile(url, myCallback) {
    let req = new XMLHttpRequest();
    req.open("GET", url);
    req.onload = function () {
      if (req.status == 200) {
        myCallback(req.responseText);
      } else {
        myCallback("Error: " + req.status);
      }
    };
    req.send();
  }
  //多重请求时出现的多重回调函数嵌套('回调地狱')
  getFile("../../for-test.html", (res) => {
    console.log(res); //test
    getFile("../for-test.html", (res) => {
      console.log(res); //Error: 404
    });
  });
</script>

Promise

Promise 为了解决多重请求时出现的多重回调函数嵌套('回调地狱')。

<script>
  function getFilePromise(url) {
    let myPromise = new Promise((myResolve, myReject) => {
      let req = new XMLHttpRequest();
      req.open("GET", url);
      req.onload = function () {
        if (req.status == 200) {
          myResolve(req.response);
        } else {
          myReject("Error: " + req.status);
        }
      };
      req.send();
    });

    return myPromise;
  }

  getFilePromise("../../for-test.html")
    .then((value) => {
      console.log(value);
    })
    .then(() => {
      return getFilePromise("../for-test.html");
    })
    .then((value) => {
      console.log(value);
    })
    .catch(function (error) {
      console.log(error);
    });
</script>

Generator 函数

"协程"(coroutine),意思是多个线程互相协作,完成异步任务。协程 A 开始执行,协程 A 执行遇到异步任务,进入暂停,执行权转移到协程 B,协程 B 完成异步任务交还执行权给协程 A,协程 A 恢复执行。

Generator 函数是协程在 ES6 的实现,最大特点就是可以交出函数的执行权(即暂停执行)。使用 function* funcname 和 yield 定义。调用 Generator 函数,会返回一个内部指针(即遍历器 )g,调用指针 g 的 next 方法,会移动内部指针,next 方法的作用是分阶段执行 Generator 函数。每次调用 next 方法,会返回一个对象,表示当前阶段的信息( value 属性和 done 属性)。value 属性是 yield 语句后面表达式的值,表示当前阶段的值;done 属性是一个布尔值,表示 Generator 函数是否执行完毕,即是否还有下一个阶段。

<script>
  function* getFileGen(url) {
    try {
      let result = yield fetch(url);
    } catch (error) {
      //捕获函数体外抛出的错误
      console.log(error);
    }
    return result;
  }
 
  var g = getFileGen("../../for-test.html");
  var result = g.next();
  console.log(result); //{value: Promise, done: false}
  result.value
    .then(function (data) {
      return data.text();
    })
    .then(function (data) {
      console.log(data); //test
      console.log(g.next()); //{value: undefined, done: true}
    });

  //抛出错误
  g.throw("出错了");

  //产生的问题:流程管理(即何时执行g.next())
</script>

async 函数

async 函数,也就是我们常说的 async/await,是在 ES2017(ES8) 引入的新特性,主要目的是为了简化使用基于 Promise 的 API 时所需的语法。async 表示函数里有异步操作,await 表示紧跟在后面的表达式需要等待结果。await关键字只在 async 函数内有效,如果在 async 函数体之外使用它,会抛出语法错误。async 函数返回一个 Promise 对象,可以使用 then 方法添加回调函数。await关键字可以跟在任意变量或者表达式之前,但通常await后面会跟一个异步过程。await使用时,会阻塞后续代码执行。

<script>
  
  async function test() {
    return "hello";
  }
  test()
    .then((res) => {
      console.log(res);
    })
    .catch((error) => {
      console.log(error);
    });

  async function test1() {
    return new Promise(function (resolve, reject) {
      if (true) {
        resolve("hello");
      } else {
        reject("error");
      }
    });
  }
  test1()
    .then((res) => {
      console.log(res);
    })
    .catch((error) => {
      console.log(error);
    });

  async function test2() {
    var result = await fetch("../../for-test.html")
      .then((response) => response.text())
      .catch((err) => console.log("Request Failed", err));
    var result1 = await "test2";
    console.log(result);
    console.log(result1);
  }
  test2();
</script>
posted @ 2023-06-21 14:38  carol2014  阅读(15)  评论(0)    收藏  举报