ES6学习笔记(十六)async函数

1.含义

ES2017 标准引入了 async 函数,使得异步操作变得更加方便。

async 函数是什么?一句话,它就是 Generator 函数的语法糖,号称异步的终极解决方案。

前文有一个 Generator 函数,依次读取两个文件。

 1 const fs = require('fs');
 2 
 3 const readFile = function (fileName) {
 4   return new Promise(function (resolve, reject) {
 5     fs.readFile(fileName, function(error, data) {
 6       if (error) return reject(error);
 7       resolve(data);
 8     });
 9   });
10 };
11 
12 const gen = function* () {
13   const f1 = yield readFile('/etc/fstab');
14   const f2 = yield readFile('/etc/shells');
15   console.log(f1.toString());
16   console.log(f2.toString());
17 };

上面代码的函数gen可以写成async函数,就是下面这样。

const asyncReadFile = async function () {
  const f1 = await readFile('/etc/fstab');
  const f2 = await readFile('/etc/shells');
  console.log(f1.toString());
  console.log(f2.toString());
};

一比较就会发现,async函数就是将 Generator 函数的星号(*)替换成async,将yield替换成await,仅此而已。

async函数对 Generator 函数的改进,体现在以下四点。

(1)内置执行器。

Generator 函数的执行必须靠执行器,所以才有了co模块,而async函数自带执行器。也就是说,async函数的执行,与普通函数一模一样,只要一行。

asyncReadFile();

上面的代码调用了asyncReadFile函数,然后它就会自动执行,输出最后结果。这完全不像 Generator 函数,需要调用next方法,或者用co模块,才能真正执行,得到最后结果。

(2)更好的语义。

asyncawait,比起星号和yield,语义更清楚了。async表示函数里有异步操作,await表示紧跟在后面的表达式需要等待结果。

(3)更广的适用性。

co模块约定,yield命令后面只能是 Thunk 函数或 Promise 对象,而async函数的await命令后面,可以是 Promise 对象和原始类型的值(数值、字符串和布尔值,但这时会自动转成立即 resolved 的 Promise 对象)。

(4)返回值是 Promise。

async函数的返回值是 Promise 对象,这比 Generator 函数的返回值是 Iterator 对象方便多了。你可以用then方法指定下一步的操作。

进一步说,async函数完全可以看作多个异步操作,包装成的一个 Promise 对象,而await命令就是内部then命令的语法糖。

2.基本用法

async函数返回一个 Promise 对象,可以使用then方法添加回调函数。当函数执行的时候,一旦遇到await就会先返回,等到异步操作完成,再接着执行函数体内后面的语句。

async function getStockPriceByName(name) {
  const symbol = await getStockSymbol(name);
  const stockPrice = await getStockPrice(symbol);
  return stockPrice;
}

getStockPriceByName('goog').then(function (result) {
  console.log(result);
});

上面代码是一个获取股票报价的函数,函数前面的async关键字,表明该函数内部有异步操作。调用该函数时,会立即返回一个Promise对象。

 1 function timeout(ms) {
 2   return new Promise((resolve) => {
 3     setTimeout(resolve, ms);
 4   });
 5 }
 6 
 7 async function asyncPrint(value, ms) {
 8   await timeout(ms);
 9   console.log(value);
10 }
11 
12 asyncPrint('hello world', 50);

上面代码指定 50 毫秒以后,输出hello world

由于async函数返回的是 Promise 对象,可以作为await命令的参数。所以,上面的例子也可以写成下面的形式。

 1 async function timeout(ms) {
 2   await new Promise((resolve) => {
 3     setTimeout(resolve, ms);
 4   });
 5 }
 6 
 7 async function asyncPrint(value, ms) {
 8   await timeout(ms);
 9   console.log(value);
10 }
11 
12 asyncPrint('hello world', 50);

async 函数有多种使用形式。

 1 // 函数声明
 2 async function foo() {}
 3 
 4 // 函数表达式
 5 const foo = async function () {};
 6 
 7 // 对象的方法
 8 let obj = { async foo() {} };
 9 obj.foo().then(...)
10 
11 // Class 的方法
12 class Storage {
13   constructor() {
14     this.cachePromise = caches.open('avatars');
15   }
16 
17   async getAvatar(name) {
18     const cache = await this.cachePromise;
19     return cache.match(`/avatars/${name}.jpg`);
20   }
21 }
22 
23 const storage = new Storage();
24 storage.getAvatar('jake').then(…);
25 
26 // 箭头函数
27 const foo = async () => {};

3.语法

async函数的语法规则总体上比较简单,难点是错误处理机制。

返回 Promise 对象 

async函数返回一个 Promise 对象。

async函数内部return语句返回的值,会成为then方法回调函数的参数。

async function f() {
  return 'hello world';
}

f().then(v => console.log(v))
// "hello world"

上面代码中,函数f内部return命令返回的值,会被then方法回调函数接收到。

async函数内部抛出错误,会导致返回的 Promise 对象变为reject状态。抛出的错误对象会被catch方法回调函数接收到。

async function f() {
  throw new Error('出错了');
}

f().then(
  v => console.log(v),
  e => console.log(e)
)
// Error: 出错了

Promise 对象的状态变化

async函数返回的 Promise 对象,必须等到内部所有await命令后面的 Promise 对象执行完,才会发生状态改变,除非遇到return语句或者抛出错误。也就是说,只有async函数内部的异步操作执行完,才会执行then方法指定的回调函数

async function getTitle(url) {
  let response = await fetch(url);
  let html = await response.text();
  return html.match(/([\s\S]+)<\/title>/i)[1<span style="color:#000000;">];
}
getTitle(</span>'https://tc39.github.io/ecma262/'<span style="color:#000000;">).then(console.log)
</span><span style="color:#008000;">//</span><span style="color:#008000;"> "ECMAScript 2017 Language Specification"</span></pre> 
   </div> 
   <p>上面代码中,函数<code>getTitle</code>内部有三个操作:抓取网页、取出文本、匹配页面标题。只有这三个操作全部完成,才会执行<code>then</code>方法里面的<code>console.log</code>。</p> 
   <h2 id="await-命令" class="await-命令">await 命令</h2> 
   <p>正常情况下,<span style="color:#ff0000;"><code>await</code></span>命令后面是一个 <span style="color:#ff0000;">Promise</span> 对象,返回该对象的结果。<span style="color:#ff0000;">如果不是 Promise 对象,就直接返回对应的值</span>。</p> 
   <div class="cnblogs_code"> 
    <pre>async <span style="color:#0000ff;">function</span><span style="color:#000000;"> f() {
  </span><span style="color:#008000;">//</span><span style="color:#008000;"> 等同于</span>
  <span style="color:#008000;">//</span><span style="color:#008000;"> return 123;</span>
  <span style="color:#0000ff;">return</span> await 123<span style="color:#000000;">;
}

f().then(v </span>=><span style="color:#000000;"> console.log(v))
</span><span style="color:#008000;">//</span><span style="color:#008000;"> 123</span></pre> 
   </div> 
   <p>上面代码中,<code>await</code>命令的参数是数值<code>123</code>,这时等同于<code>return 123</code>。</p> 
   <p>另一种情况是,<span style="color:#ff0000;"><code>await</code></span>命令后面是一个<span style="color:#ff0000;"><code>thenable</code></span>对象(即定义<span style="color:#ff0000;"><code>then</code></span>方法的对象),那么<code>await</code>会将其等同于 Promise 对象。</p> 
   <div class="cnblogs_code"> 
    <pre><span style="color:#008080;"> 1</span> <span style="color:#000000;">class Sleep {
</span><span style="color:#008080;"> 2</span> <span style="color:#000000;">  constructor(timeout) {
</span><span style="color:#008080;"> 3</span>     <span style="color:#0000ff;">this</span>.timeout =<span style="color:#000000;"> timeout;
</span><span style="color:#008080;"> 4</span> <span style="color:#000000;">  }
</span><span style="color:#008080;"> 5</span> <span style="color:#000000;"><span style="color:#ff0000;">  then</span>(resolve, reject) {
</span><span style="color:#008080;"> 6</span>     const startTime =<span style="color:#000000;"> Date.now();
</span><span style="color:#008080;"> 7</span> <span style="color:#000000;">    setTimeout(
</span><span style="color:#008080;"> 8</span>       () => resolve(Date.now() -<span style="color:#000000;"> startTime),
</span><span style="color:#008080;"> 9</span>       <span style="color:#0000ff;">this</span><span style="color:#000000;">.timeout
</span><span style="color:#008080;">10</span> <span style="color:#000000;">    );
</span><span style="color:#008080;">11</span> <span style="color:#000000;">  }
</span><span style="color:#008080;">12</span> <span style="color:#000000;">}
</span><span style="color:#008080;">13</span> 
<span style="color:#008080;">14</span> (async () =><span style="color:#000000;"> {
</span><span style="color:#008080;">15</span>   const actualTime = await <span style="color:#0000ff;">new</span> Sleep(1000<span style="color:#000000;">);
</span><span style="color:#008080;">16</span> <span style="color:#000000;">  console.log(actualTime);
</span><span style="color:#008080;">17</span> })();</pre> 
   </div> 
   <p>上面代码中,<code>await</code>命令后面是一个<code>Sleep</code>对象的实例。这个实例不是 Promise 对象,但是因为定义了<code>then</code>方法,<code>await</code>会将其视为<code>Promise</code>处理。</p> 
   <p><code>await</code>命令后面的 Promise 对象如果变为<code>reject</code>状态,则<code>reject</code>的参数会被<code>catch</code>方法的回调函数接收到。</p> 
   <div class="cnblogs_code"> 
    <pre>async <span style="color:#0000ff;">function</span><span style="color:#000000;"> f() {
  await Promise.reject(</span>'出错了'<span style="color:#000000;">);
}

f()
.then(v </span>=><span style="color:#000000;"> console.log(v))
.</span><span style="color:#0000ff;">catch</span>(e =><span style="color:#000000;"> console.log(e))
</span><span style="color:#008000;">//</span><span style="color:#008000;"> 出错了</span></pre> 
   </div> 
   <p>注意,上面代码中,<code>await</code>语句前面没有<code>return</code>,但是<code>reject</code>方法的参数依然传入了<code>catch</code>方法的回调函数。这里如果在<code>await</code>前面加上<code>return</code>,效果是一样的。</p> 
   <p>任何一个<code>await</code>语句后面的 Promise 对象变为<code>reject</code>状态,那么整个<code>async</code>函数都会中断执行。</p> 
   <div class="cnblogs_code"> 
    <pre>async <span style="color:#0000ff;">function</span><span style="color:#000000;"> f() {
  await Promise.reject(</span>'出错了'<span style="color:#000000;">);
  await Promise.resolve(</span>'hello world'); <span style="color:#008000;">//</span><span style="color:#008000;"> 不会执行</span>
}</pre> 
   </div> 
   <p>上面代码中,第二个<code>await</code>语句是不会执行的,因为第一个<code>await</code>语句状态变成了<code>reject</code>。</p> 
   <p>有时,我们希望即使前一个异步操作失败,也不要中断后面的异步操作。这时可以将第一个<code>await</code>放在<code>try...catch</code>结构里面,这样不管这个异步操作是否成功,第二个<code>await</code>都会执行。</p> 
   <div class="cnblogs_code"> 
    <pre>async <span style="color:#0000ff;">function</span><span style="color:#000000;"> f() {
  </span><span style="color:#0000ff;">try</span><span style="color:#000000;"> {
    await Promise.reject(</span>'出错了'<span style="color:#000000;">);
  } </span><span style="color:#0000ff;">catch</span><span style="color:#000000;">(e) {
  }
  </span><span style="color:#0000ff;">return</span> await Promise.resolve('hello world'<span style="color:#000000;">);
}

f()
.then(v </span>=><span style="color:#000000;"> console.log(v))
</span><span style="color:#008000;">//</span><span style="color:#008000;"> hello world</span></pre> 
   </div> 
   <p>另一种方法是<code>await</code>后面的 Promise 对象再跟一个<code>catch</code>方法,处理前面可能出现的错误。</p> 
   <div class="cnblogs_code"> 
    <pre>async <span style="color:#0000ff;">function</span><span style="color:#000000;"> f() {
  await Promise.reject(</span>'出错了'<span style="color:#000000;">)
    .</span><span style="color:#0000ff;">catch</span>(e =><span style="color:#000000;"> console.log(e));
  </span><span style="color:#0000ff;">return</span> await Promise.resolve('hello world'<span style="color:#000000;">);
}

f()
.then(v </span>=><span style="color:#000000;"> console.log(v))
</span><span style="color:#008000;">//</span><span style="color:#008000;"> 出错了</span><span style="color:#008000;">
//</span><span style="color:#008000;"> hello world</span></pre> 
   </div> 
   <h2 id="错误处理" class="错误处理">错误处理</h2> 
   <p>如果<code>await</code>后面的异步操作出错,那么等同于<code>async</code>函数返回的 Promise 对象被<code>reject</code>。</p> 
   <div class="cnblogs_code"> 
    <pre>async <span style="color:#0000ff;">function</span><span style="color:#000000;"> f() {
  await </span><span style="color:#0000ff;">new</span> Promise(<span style="color:#0000ff;">function</span><span style="color:#000000;"> (resolve, reject) {
    </span><span style="color:#0000ff;">throw</span> <span style="color:#0000ff;">new</span> Error('出错了'<span style="color:#000000;">);
  });
}

f()
.then(v </span>=><span style="color:#000000;"> console.log(v))
.</span><span style="color:#0000ff;">catch</span>(e =><span style="color:#000000;"> console.log(e))
</span><span style="color:#008000;">//</span><span style="color:#008000;"> Error:出错了</span></pre> 
   </div> 
   <p>上面代码中,<code>async</code>函数<code>f</code>执行后,<code>await</code>后面的 Promise 对象会抛出一个错误对象,导致<code>catch</code>方法的回调函数被调用,它的参数就是抛出的错误对象。具体的执行机制,可以参考后文的“async 函数的实现原理”。</p> 
   <p>防止出错的方法,也是将其放在<code>try...catch</code>代码块之中。</p> 
   <div class="cnblogs_code"> 
    <pre>async <span style="color:#0000ff;">function</span><span style="color:#000000;"> f() {
  </span><span style="color:#0000ff;">try</span><span style="color:#000000;"> {
    await </span><span style="color:#0000ff;">new</span> Promise(<span style="color:#0000ff;">function</span><span style="color:#000000;"> (resolve, reject) {
      </span><span style="color:#0000ff;">throw</span> <span style="color:#0000ff;">new</span> Error('出错了'<span style="color:#000000;">);
    });
  } </span><span style="color:#0000ff;">catch</span><span style="color:#000000;">(e) {
  }
  </span><span style="color:#0000ff;">return</span> await('hello world'<span style="color:#000000;">);
}</span></pre> 
   </div> 
   <p>如果有多个<code>await</code>命令,可以统一放在<span style="color:#ff0000;"><code>try...catch</code></span>结构中。</p> 
   <div class="cnblogs_code"> 
    <pre><span style="color:#008080;"> 1</span> async <span style="color:#0000ff;">function</span><span style="color:#000000;"> main() {
</span><span style="color:#008080;"> 2</span>   <span style="color:#0000ff;">try</span><span style="color:#000000;"> {
</span><span style="color:#008080;"> 3</span>     const val1 =<span style="color:#000000;"> await firstStep();
</span><span style="color:#008080;"> 4</span>     const val2 =<span style="color:#000000;"> await secondStep(val1);
</span><span style="color:#008080;"> 5</span>     const val3 =<span style="color:#000000;"> await thirdStep(val1, val2);
</span><span style="color:#008080;"> 6</span> 
<span style="color:#008080;"> 7</span>     console.log('Final: '<span style="color:#000000;">, val3);
</span><span style="color:#008080;"> 8</span> <span style="color:#000000;">  }
</span><span style="color:#008080;"> 9</span>   <span style="color:#0000ff;">catch</span><span style="color:#000000;"> (err) {
</span><span style="color:#008080;">10</span> <span style="color:#000000;">    console.error(err);
</span><span style="color:#008080;">11</span> <span style="color:#000000;">  }
</span><span style="color:#008080;">12</span> }</pre> 
   </div> 
   <p>下面的例子使用<code>try...catch</code>结构,实现多次重复尝试。</p> 
   <div class="cnblogs_code"> 
    <pre><span style="color:#008080;"> 1</span> const superagent = require('superagent'<span style="color:#000000;">);
</span><span style="color:#008080;"> 2</span> const NUM_RETRIES = 3<span style="color:#000000;">;
</span><span style="color:#008080;"> 3</span> 
<span style="color:#008080;"> 4</span> async <span style="color:#0000ff;">function</span><span style="color:#000000;"> test() {
</span><span style="color:#008080;"> 5</span> <span style="color:#000000;">  let i;
</span><span style="color:#008080;"> 6</span>   <span style="color:#0000ff;">for</span> (i = 0; i < NUM_RETRIES; ++<span style="color:#000000;">i) {
</span><span style="color:#008080;"> 7</span>     <span style="color:#0000ff;">try</span><span style="color:#000000;"> {
</span><span style="color:#008080;"> 8</span>       await superagent.get('http://google.com/this-throws-an-error'<span style="color:#000000;">);
</span><span style="color:#008080;"> 9</span>       <span style="color:#0000ff;">break</span><span style="color:#000000;">;
</span><span style="color:#008080;">10</span>     } <span style="color:#0000ff;">catch</span><span style="color:#000000;">(err) {}
</span><span style="color:#008080;">11</span> <span style="color:#000000;">  }
</span><span style="color:#008080;">12</span>   console.log(i); <span style="color:#008000;">//</span><span style="color:#008000;"> 3</span>
<span style="color:#008080;">13</span> <span style="color:#000000;">}
</span><span style="color:#008080;">14</span> 
<span style="color:#008080;">15</span> test();</pre> 
   </div> 
   <p>上面代码中,如果<code>await</code>操作成功,就会使用<code>break</code>语句退出循环;如果失败,会被<code>catch</code>语句捕捉,然后进入下一轮循环。这个操作很神奇啊。</p> 
   <h2 id="使用注意点" class="使用注意点">使用注意点 </h2> 
   <p><span style="color:#ff0000;">第一点</span>,前面已经说过,<span style="color:#ff0000;"><code>await</code></span>命令后面的<span style="color:#ff0000;"><code>Promise</code></span>对象,运行结果可能是<span style="color:#ff0000;"><code>rejected</code></span>,所以最好把<span style="color:#ff0000;"><code>await</code></span>命令放在<span style="color:#ff0000;"><code>try...catch</code></span>代码块中。</p> 
   <div class="cnblogs_code"> 
    <pre><span style="color:#008080;"> 1</span> async <span style="color:#0000ff;">function</span><span style="color:#000000;"> myFunction() {
</span><span style="color:#008080;"> 2</span>   <span style="color:#0000ff;">try</span><span style="color:#000000;"> {
</span><span style="color:#008080;"> 3</span> <span style="color:#000000;">    await somethingThatReturnsAPromise();
</span><span style="color:#008080;"> 4</span>   } <span style="color:#0000ff;">catch</span><span style="color:#000000;"> (err) {
</span><span style="color:#008080;"> 5</span> <span style="color:#000000;">    console.log(err);
</span><span style="color:#008080;"> 6</span> <span style="color:#000000;">  }
</span><span style="color:#008080;"> 7</span> <span style="color:#000000;">}
</span><span style="color:#008080;"> 8</span> 
<span style="color:#008080;"> 9</span> <span style="color:#008000;">//</span><span style="color:#008000;"> 另一种写法</span>
<span style="color:#008080;">10</span> 
<span style="color:#008080;">11</span> async <span style="color:#0000ff;">function</span><span style="color:#000000;"> myFunction() {
</span><span style="color:#008080;">12</span> <span style="color:#000000;">  await somethingThatReturnsAPromise()
</span><span style="color:#008080;">13</span>   .<span style="color:#0000ff;">catch</span>(<span style="color:#0000ff;">function</span><span style="color:#000000;"> (err) {
</span><span style="color:#008080;">14</span> <span style="color:#000000;">    console.log(err);
</span><span style="color:#008080;">15</span> <span style="color:#000000;">  });
</span><span style="color:#008080;">16</span> }</pre> 
   </div> 
   <p><span style="color:#ff0000;">第二点,多个<code>await</code>命令后面的异步操作,如果不存在继发关系,最好让它们同时触发</span>。</p> 
   <div class="cnblogs_code"> 
    <pre>let foo =<span style="color:#000000;"> await getFoo();
let bar </span>= await getBar();</pre> 
   </div> 
   <p>上面代码中,<code>getFoo</code>和<code>getBar</code>是两个独立的异步操作(即互不依赖),被写成继发关系。这样比较耗时,因为只有<code>getFoo</code>完成以后,才会执行<code>getBar</code>,完全可以让它们同时触发。</p> 
   <div class="cnblogs_code"> 
    <pre><span style="color:#008000;">//</span><span style="color:#008000;"> 写法一</span>
let [foo, bar] =<span style="color:#000000;"> await Promise.all([getFoo(), getBar()]);

</span><span style="color:#008000;">//</span><span style="color:#008000;"> 写法二</span>
let fooPromise =<span style="color:#000000;"> getFoo();
let barPromise </span>=<span style="color:#000000;"> getBar();
let foo </span>=<span style="color:#000000;"> await fooPromise;
let bar </span>= await barPromise;</pre> 
   </div> 
   <p>上面两种写法,<code>getFoo</code>和<code>getBar</code>都是同时触发,这样就会缩短程序的执行时间。</p> 
   <p><span style="color:#ff0000;">第三点</span>,<span style="color:#ff0000;"><code>await</code></span>命令只能用在<span style="color:#ff0000;"><code>async</code></span>函数之中,如果用在普通函数,就会报错。</p> 
   <div class="cnblogs_code"> 
    <pre>async <span style="color:#0000ff;">function</span><span style="color:#000000;"> dbFuc(db) {
  let docs </span>=<span style="color:#000000;"> [{}, {}, {}];

  </span><span style="color:#008000;">//</span><span style="color:#008000;"> 报错</span>
  docs.forEach(<span style="color:#0000ff;">function</span><span style="color:#000000;"> (doc) {
    await db.post(doc);
  });
}</span></pre> 
   </div> 
   <p>上面代码会报错,因为<code>await</code>用在普通函数之中了。但是,如果将<code>forEach</code>方法的参数改成<code>async</code>函数,也有问题。</p> 
   <div class="cnblogs_code"> 
    <pre><span style="color:#0000ff;">function</span> dbFuc(db) { <span style="color:#008000;">//</span><span style="color:#008000;">这里不需要 async</span>
  let docs =<span style="color:#000000;"> [{}, {}, {}];

  </span><span style="color:#008000;">//</span><span style="color:#008000;"> 可能得到错误结果</span>
  docs.forEach(async <span style="color:#0000ff;">function</span><span style="color:#000000;"> (doc) {
    await db.post(doc);
  });
}</span></pre> 
   </div> 
   <p>上面代码可能不会正常工作,原因是这时三个<code>db.post</code>操作将是并发执行,也就是同时执行,而不是继发执行。正确的写法是采用<code>for</code>循环。</p> 
   <div class="cnblogs_code"> 
    <pre>async <span style="color:#0000ff;">function</span><span style="color:#000000;"> dbFuc(db) {
  let docs </span>=<span style="color:#000000;"> [{}, {}, {}];

  </span><span style="color:#0000ff;">for</span><span style="color:#000000;"> (let doc of docs) {
    await db.post(doc);
  }
}</span></pre> 
   </div> 
   <p>如果确实希望多个请求并发执行,可以使用<span style="color:#ff0000;"><code>Promise.all</code></span>方法。当三个请求都会<code>resolved</code>时,下面两种写法效果相同。</p> 
   <div class="cnblogs_code"> 
    <pre><span style="color:#008080;"> 1</span> async <span style="color:#0000ff;">function</span><span style="color:#000000;"> dbFuc(db) {
</span><span style="color:#008080;"> 2</span>   let docs =<span style="color:#000000;"> [{}, {}, {}];
</span><span style="color:#008080;"> 3</span>   let promises = docs.map((doc) =><span style="color:#000000;"> db.post(doc));
</span><span style="color:#008080;"> 4</span> 
<span style="color:#008080;"> 5</span>   let results =<span style="color:#000000;"> await Promise.all(promises);
</span><span style="color:#008080;"> 6</span> <span style="color:#000000;">  console.log(results);
</span><span style="color:#008080;"> 7</span> <span style="color:#000000;">}
</span><span style="color:#008080;"> 8</span> 
<span style="color:#008080;"> 9</span> <span style="color:#008000;">//</span><span style="color:#008000;"> 或者使用下面的写法</span>
<span style="color:#008080;">10</span> 
<span style="color:#008080;">11</span> async <span style="color:#0000ff;">function</span><span style="color:#000000;"> dbFuc(db) {
</span><span style="color:#008080;">12</span>   let docs =<span style="color:#000000;"> [{}, {}, {}];
</span><span style="color:#008080;">13</span>   let promises = docs.map((doc) =><span style="color:#000000;"> db.post(doc));
</span><span style="color:#008080;">14</span> 
<span style="color:#008080;">15</span>   let results =<span style="color:#000000;"> [];
</span><span style="color:#008080;">16</span>   <span style="color:#0000ff;">for</span><span style="color:#000000;"> (let promise of promises) {
</span><span style="color:#008080;">17</span> <span style="color:#000000;">    results.push(await promise);
</span><span style="color:#008080;">18</span> <span style="color:#000000;">  }
</span><span style="color:#008080;">19</span> <span style="color:#000000;">  console.log(results);
</span><span style="color:#008080;">20</span> }</pre> 
   </div> 
   <p>目前,<code>esm</code>模块加载器支持顶层<code>await</code>,即<code>await</code>命令可以不放在 async 函数里面,直接使用。</p> 
   <div class="cnblogs_code"> 
    <pre><span style="color:#008000;">//</span><span style="color:#008000;"> async 函数的写法</span>
const start = async () =><span style="color:#000000;"> {
  const res </span>= await fetch('google.com'<span style="color:#000000;">);
  </span><span style="color:#0000ff;">return</span><span style="color:#000000;"> res.text();
};

start().then(console.log);

</span><span style="color:#008000;">//</span><span style="color:#008000;"> 顶层 await 的写法</span>
const res = await fetch('google.com'<span style="color:#000000;">);
console.log(await res.text());</span></pre> 
   </div> 
   <p>上面代码中,第二种写法的脚本必须使用<code>esm</code>加载器,才会生效。</p> 
   <p><span style="color:#ff0000;">第四点</span>,async 函数可以保留运行堆栈。</p> 
   <div class="cnblogs_code"> 
    <pre>const a = () =><span style="color:#000000;"> {
  b().then(() </span>=><span style="color:#000000;"> c());
};</span></pre> 
   </div> 
   <p>上面代码中,函数<code>a</code>内部运行了一个异步任务<code>b()</code>。当<code>b()</code>运行的时候,函数<code>a()</code>不会中断,而是继续执行。等到<code>b()</code>运行结束,可能<code>a()</code>早就运行结束了,<code>b()</code>所在的上下文环境已经消失了。如果<code>b()</code>或<code>c()</code>报错,错误堆栈将不包括<code>a()</code>。</p> 
   <p>现在将这个例子改成<code>async</code>函数。</p> 
   <div class="cnblogs_code"> 
    <pre>const a = async () =><span style="color:#000000;"> {
  await b();
  c();
};</span></pre> 
   </div> 
   <p>上面代码中,<code>b()</code>运行的时候,<code>a()</code>是暂停执行,上下文环境都保存着。一旦<code>b()</code>或<code>c()</code>报错,错误堆栈将包括<code>a()</code>。</p> 
   <h1 id="async-函数的实现原理" class="async-函数的实现原理">4.async 函数的实现原理</h1> 
   <p><span style="color:#ff0000;">async 函数的实现原理,就是将 Generator 函数和自动执行器,包装在一个函数里</span>。</p> 
   <div class="cnblogs_code"> 
    <pre>async <span style="color:#0000ff;">function</span><span style="color:#000000;"> fn(args) {
  </span><span style="color:#008000;">//</span><span style="color:#008000;"> ...</span>
<span style="color:#000000;">}

</span><span style="color:#008000;">//</span><span style="color:#008000;"> 等同于</span>

<span style="color:#0000ff;">function</span><span style="color:#000000;"> fn(args) {
  </span><span style="color:#0000ff;">return</span> spawn(<span style="color:#0000ff;">function</span>*<span style="color:#000000;"> () {
    </span><span style="color:#008000;">//</span><span style="color:#008000;"> ...</span>
<span style="color:#000000;">  });
}</span></pre> 
   </div> 
   <p>所有的<code>async</code>函数都可以写成上面的第二种形式,其中的<code>spawn</code>函数就是自动执行器。</p> 
   <p>下面给出<code>spawn</code>函数的实现,基本就是前文自动执行器的翻版。</p> 
   <div class="cnblogs_code"> 
    <pre><span style="color:#008080;"> 1</span> <span style="color:#0000ff;">function</span><span style="color:#000000;"> spawn(genF) {
</span><span style="color:#008080;"> 2</span>   <span style="color:#0000ff;">return</span> <span style="color:#0000ff;">new</span> Promise(<span style="color:#0000ff;">function</span><span style="color:#000000;">(resolve, reject) {
</span><span style="color:#008080;"> 3</span>     const gen =<span style="color:#000000;"> genF();
</span><span style="color:#008080;"> 4</span>     <span style="color:#0000ff;">function</span><span style="color:#000000;"> step(nextF) {
</span><span style="color:#008080;"> 5</span> <span style="color:#000000;">      let next;
</span><span style="color:#008080;"> 6</span>       <span style="color:#0000ff;">try</span><span style="color:#000000;"> {
</span><span style="color:#008080;"> 7</span>         next =<span style="color:#000000;"> nextF();
</span><span style="color:#008080;"> 8</span>       } <span style="color:#0000ff;">catch</span><span style="color:#000000;">(e) {
</span><span style="color:#008080;"> 9</span>         <span style="color:#0000ff;">return</span><span style="color:#000000;"> reject(e);
</span><span style="color:#008080;">10</span> <span style="color:#000000;">      }
</span><span style="color:#008080;">11</span>       <span style="color:#0000ff;">if</span><span style="color:#000000;">(next.done) {
</span><span style="color:#008080;">12</span>         <span style="color:#0000ff;">return</span><span style="color:#000000;"> resolve(next.value);
</span><span style="color:#008080;">13</span> <span style="color:#000000;">      }
</span><span style="color:#008080;">14</span>       Promise.resolve(next.value).then(<span style="color:#0000ff;">function</span><span style="color:#000000;">(v) {
</span><span style="color:#008080;">15</span>         step(<span style="color:#0000ff;">function</span>() { <span style="color:#0000ff;">return</span><span style="color:#000000;"> gen.next(v); });
</span><span style="color:#008080;">16</span>       }, <span style="color:#0000ff;">function</span><span style="color:#000000;">(e) {
</span><span style="color:#008080;">17</span>         step(<span style="color:#0000ff;">function</span>() { <span style="color:#0000ff;">return</span> gen.<span style="color:#0000ff;">throw</span><span style="color:#000000;">(e); });
</span><span style="color:#008080;">18</span> <span style="color:#000000;">      });
</span><span style="color:#008080;">19</span> <span style="color:#000000;">    }
</span><span style="color:#008080;">20</span>     step(<span style="color:#0000ff;">function</span>() { <span style="color:#0000ff;">return</span><span style="color:#000000;"> gen.next(undefined); });
</span><span style="color:#008080;">21</span> <span style="color:#000000;">  });
</span><span style="color:#008080;">22</span> }</pre> 
   </div> 
   <h1 id="与其他异步处理方法的比较" class="与其他异步处理方法的比较">5.与其他异步处理方法的比较</h1> 
   <p>我们通过一个例子,来看 <span style="color:#ff0000;">async</span> 函数与 <span style="color:#ff0000;">Promise</span>、<span style="color:#ff0000;">Generator</span> 函数的<span style="color:#ff0000;">比较</span>。</p> 
   <p>假定某个 DOM 元素上面,部署了一系列的动画,前一个动画结束,才能开始后一个。如果当中有一个动画出错,就不再往下执行,返回上一个成功执行的动画的返回值。</p> 
   <p>首先是 Promise 的写法。</p> 
   <div class="cnblogs_code"> 
    <pre><span style="color:#008080;"> 1</span> <span style="color:#0000ff;">function</span><span style="color:#000000;"> chainAnimationsPromise(elem, animations) {
</span><span style="color:#008080;"> 2</span> 
<span style="color:#008080;"> 3</span>   <span style="color:#008000;">//</span><span style="color:#008000;"> 变量ret用来保存上一个动画的返回值</span>
<span style="color:#008080;"> 4</span>   let ret = <span style="color:#0000ff;">null</span><span style="color:#000000;">;
</span><span style="color:#008080;"> 5</span> 
<span style="color:#008080;"> 6</span>   <span style="color:#008000;">//</span><span style="color:#008000;"> 新建一个空的Promise</span>
<span style="color:#008080;"> 7</span>   let p =<span style="color:#000000;"> Promise.resolve();
</span><span style="color:#008080;"> 8</span> 
<span style="color:#008080;"> 9</span>   <span style="color:#008000;">//</span><span style="color:#008000;"> 使用then方法,添加所有动画</span>
<span style="color:#008080;">10</span>   <span style="color:#0000ff;">for</span><span style="color:#000000;">(let anim of animations) {
</span><span style="color:#008080;">11</span>     p = p.then(<span style="color:#0000ff;">function</span><span style="color:#000000;">(val) {
</span><span style="color:#008080;">12</span>       ret =<span style="color:#000000;"> val;
</span><span style="color:#008080;">13</span>       <span style="color:#0000ff;">return</span><span style="color:#000000;"> anim(elem);
</span><span style="color:#008080;">14</span> <span style="color:#000000;">    });
</span><span style="color:#008080;">15</span> <span style="color:#000000;">  }
</span><span style="color:#008080;">16</span> 
<span style="color:#008080;">17</span>   <span style="color:#008000;">//</span><span style="color:#008000;"> 返回一个部署了错误捕捉机制的Promise</span>
<span style="color:#008080;">18</span>   <span style="color:#0000ff;">return</span> p.<span style="color:#0000ff;">catch</span>(<span style="color:#0000ff;">function</span><span style="color:#000000;">(e) {
</span><span style="color:#008080;">19</span>     <span style="color:#008000;">/*</span><span style="color:#008000;"> 忽略错误,继续执行 </span><span style="color:#008000;">*/</span>
<span style="color:#008080;">20</span>   }).then(<span style="color:#0000ff;">function</span><span style="color:#000000;">() {
</span><span style="color:#008080;">21</span>     <span style="color:#0000ff;">return</span><span style="color:#000000;"> ret;
</span><span style="color:#008080;">22</span> <span style="color:#000000;">  });
</span><span style="color:#008080;">23</span> 
<span style="color:#008080;">24</span> }</pre> 
   </div> 
   <p>虽然 Promise 的写法比回调函数的写法大大改进,但是一眼看上去,代码完全都是 Promise 的 API(<code>then</code>、<code>catch</code>等等),操作本身的语义反而不容易看出来。</p> 
   <p>接着是 Generator 函数的写法。</p> 
   <div class="cnblogs_code"> 
    <pre><span style="color:#008080;"> 1</span> <span style="color:#0000ff;">function</span><span style="color:#000000;"> chainAnimationsGenerator(elem, animations) {
</span><span style="color:#008080;"> 2</span> 
<span style="color:#008080;"> 3</span>   <span style="color:#0000ff;">return</span> spawn(<span style="color:#0000ff;">function</span>*<span style="color:#000000;">() {
</span><span style="color:#008080;"> 4</span>     let ret = <span style="color:#0000ff;">null</span><span style="color:#000000;">;
</span><span style="color:#008080;"> 5</span>     <span style="color:#0000ff;">try</span><span style="color:#000000;"> {
</span><span style="color:#008080;"> 6</span>       <span style="color:#0000ff;">for</span><span style="color:#000000;">(let anim of animations) {
</span><span style="color:#008080;"> 7</span>         ret =<span style="color:#000000;"> yield anim(elem);
</span><span style="color:#008080;"> 8</span> <span style="color:#000000;">      }
</span><span style="color:#008080;"> 9</span>     } <span style="color:#0000ff;">catch</span><span style="color:#000000;">(e) {
</span><span style="color:#008080;">10</span>       <span style="color:#008000;">/*</span><span style="color:#008000;"> 忽略错误,继续执行 </span><span style="color:#008000;">*/</span>
<span style="color:#008080;">11</span> <span style="color:#000000;">    }
</span><span style="color:#008080;">12</span>     <span style="color:#0000ff;">return</span><span style="color:#000000;"> ret;
</span><span style="color:#008080;">13</span> <span style="color:#000000;">  });
</span><span style="color:#008080;">14</span> 
<span style="color:#008080;">15</span> }</pre> 
   </div> 
   <p>上面代码使用 Generator 函数遍历了每个动画,语义比 Promise 写法更清晰,用户定义的操作全部都出现在<code>spawn</code>函数的内部。这个写法的问题在于,必须有一个任务运行器,自动执行 Generator 函数,上面代码的<code>spawn</code>函数就是自动执行器,它返回一个 Promise 对象,而且必须保证<code>yield</code>语句后面的表达式,必须返回一个 Promise。</p> 
   <p>最后是 async 函数的写法。</p> 
   <div class="cnblogs_code"> 
    <pre><span style="color:#008080;"> 1</span> async <span style="color:#0000ff;">function</span><span style="color:#000000;"> chainAnimationsAsync(elem, animations) {
</span><span style="color:#008080;"> 2</span>   let ret = <span style="color:#0000ff;">null</span><span style="color:#000000;">;
</span><span style="color:#008080;"> 3</span>   <span style="color:#0000ff;">try</span><span style="color:#000000;"> {
</span><span style="color:#008080;"> 4</span>     <span style="color:#0000ff;">for</span><span style="color:#000000;">(let anim of animations) {
</span><span style="color:#008080;"> 5</span>       ret =<span style="color:#000000;"> await anim(elem);
</span><span style="color:#008080;"> 6</span> <span style="color:#000000;">    }
</span><span style="color:#008080;"> 7</span>   } <span style="color:#0000ff;">catch</span><span style="color:#000000;">(e) {
</span><span style="color:#008080;"> 8</span>     <span style="color:#008000;">/*</span><span style="color:#008000;"> 忽略错误,继续执行 </span><span style="color:#008000;">*/</span>
<span style="color:#008080;"> 9</span> <span style="color:#000000;">  }
</span><span style="color:#008080;">10</span>   <span style="color:#0000ff;">return</span><span style="color:#000000;"> ret;
</span><span style="color:#008080;">11</span> }</pre> 
   </div> 
   <p>可以看到 Async 函数的实现最简洁,最符合语义,几乎没有语义不相关的代码。它将 Generator 写法中的<span style="color:#ff0000;">自动执行器</span>,改在<span style="color:#ff0000;">语言层面</span>提供,不暴露给用户,因此代码量最少。如果使用 Generator 写法,自动执行器需要用户自己提供。</p> 
   <h1 id="实例:按顺序完成异步操作" class="实例:按顺序完成异步操作">6.实例:按顺序完成异步操作</h1> 
   <p>实际开发中,经常遇到一组异步操作,需要按照顺序完成。比如,依次远程读取一组 URL,然后按照读取的顺序输出结果。</p> 
   <p>Promise 的写法如下。</p> 
   <div class="cnblogs_code"> 
    <pre><span style="color:#008080;"> 1</span> <span style="color:#0000ff;">function</span><span style="color:#000000;"> logInOrder(urls) {
</span><span style="color:#008080;"> 2</span>   <span style="color:#008000;">//</span><span style="color:#008000;"> 远程读取所有URL</span>
<span style="color:#008080;"> 3</span>   const textPromises = urls.map(url =><span style="color:#000000;"> {
</span><span style="color:#008080;"> 4</span>     <span style="color:#0000ff;">return</span> fetch(url).then(response =><span style="color:#000000;"> response.text());
</span><span style="color:#008080;"> 5</span> <span style="color:#000000;">  });
</span><span style="color:#008080;"> 6</span> 
<span style="color:#008080;"> 7</span>   <span style="color:#008000;">//</span><span style="color:#008000;"> 按次序输出</span>
<span style="color:#008080;"> 8</span>   textPromises.reduce((chain, textPromise) =><span style="color:#000000;"> {
</span><span style="color:#008080;"> 9</span>     <span style="color:#0000ff;">return</span> chain.then(() =><span style="color:#000000;"> textPromise)
</span><span style="color:#008080;">10</span>       .then(text =><span style="color:#000000;"> console.log(text));
</span><span style="color:#008080;">11</span> <span style="color:#000000;">  }, Promise.resolve());
</span><span style="color:#008080;">12</span> }</pre> 
   </div> 
   <p>上面代码使用<code>fetch</code>方法,同时远程读取一组 URL。每个<code>fetch</code>操作都返回一个 Promise 对象,放入<code>textPromises</code>数组。然后,<code>reduce</code>方法依次处理每个 Promise 对象,然后使用<code>then</code>,将所有 Promise 对象连起来,因此就可以依次输出结果。</p> 
   <p>这种写法不太直观,可读性比较差。下面是 async 函数实现。</p> 
   <div class="cnblogs_code"> 
    <pre>async <span style="color:#0000ff;">function</span><span style="color:#000000;"> logInOrder(urls) {
  </span><span style="color:#0000ff;">for</span><span style="color:#000000;"> (const url of urls) {
    const response </span>=<span style="color:#000000;"> await fetch(url);
    console.log(await response.text());
  }
}</span></pre> 
   </div> 
   <p>上面代码确实大大简化,问题是所有远程操作都是继发。只有前一个 URL 返回结果,才会去读取下一个 URL,这样做效率很差,非常浪费时间。我们需要的是<span style="color:#ff0000;">并发发出远程请求</span>。</p> 
   <div class="cnblogs_code"> 
    <pre><span style="color:#008080;"> 1</span> async <span style="color:#0000ff;">function</span><span style="color:#000000;"> logInOrder(urls) {
</span><span style="color:#008080;"> 2</span>   <span style="color:#008000;">//</span><span style="color:#008000;"> 并发读取远程URL</span>
<span style="color:#008080;"> 3</span>   const textPromises = urls.map(async url =><span style="color:#000000;"> {
</span><span style="color:#008080;"> 4</span>     const response =<span style="color:#000000;"> await fetch(url);
</span><span style="color:#008080;"> 5</span>     <span style="color:#0000ff;">return</span><span style="color:#000000;"> response.text();
</span><span style="color:#008080;"> 6</span> <span style="color:#000000;">  });
</span><span style="color:#008080;"> 7</span> 
<span style="color:#008080;"> 8</span>   <span style="color:#008000;">//</span><span style="color:#008000;"> 按次序输出</span>
<span style="color:#008080;"> 9</span>   <span style="color:#0000ff;">for</span><span style="color:#000000;"> (const textPromise of textPromises) {
</span><span style="color:#008080;">10</span> <span style="color:#000000;">    console.log(await textPromise);
</span><span style="color:#008080;">11</span> <span style="color:#000000;">  }
</span><span style="color:#008080;">12</span> }</pre> 
   </div> 
   <p>上面代码中,虽然<code>map</code>方法的参数是<code>async</code>函数,但它是并发执行的,因为<span style="color:#ff0000;">只有<code>async</code>函数内部是继发执行,外部不受影响</span>。后面的<code>for..of</code>循环内部使用了<code>await</code>,因此实现了按顺序输出。</p> 
   <h1 id="异步遍历器" class="异步遍历器">7.异步遍历器</h1> 
   <p>《遍历器》一章说过,Iterator 接口是一种数据遍历的协议,只要调用遍历器对象的<code>next</code>方法,就会得到一个对象,表示当前遍历指针所在的那个位置的信息。<code>next</code>方法返回的对象的结构是<code>{value, done}</code>,其中<code>value</code>表示当前的数据的值,<code>done</code>是一个布尔值,表示遍历是否结束。</p> 
   <p>这里隐含着一个规定,<code>next</code>方法必须是同步的,只要调用就必须立刻返回值。也就是说,一旦执行<code>next</code>方法,就必须同步地得到<code>value</code>和<code>done</code>这两个属性。如果遍历指针正好指向同步操作,当然没有问题,但对于异步操作,就不太合适了。目前的解决方法是,Generator 函数里面的异步操作,返回一个 Thunk 函数或者 Promise 对象,即<code>value</code>属性是一个 Thunk 函数或者 Promise 对象,等待以后返回真正的值,而<code>done</code>属性则还是同步产生的。</p> 
   <p>ES2018 引入了“异步遍历器”(Async Iterator),为异步操作提供原生的遍历器接口,即<code>value</code>和<code>done</code>这两个属性都是异步产生。</p> 
   <h2 id="异步遍历的接口" class="异步遍历的接口">异步遍历的接口</h2> 
   <p>异步遍历器的最大的语法特点,就是调用遍历器的<code>next</code>方法,返回的是一个 Promise 对象。</p> 
   <div class="cnblogs_code"> 
    <pre><span style="color:#000000;">asyncIterator
  .next()
  .then(
    ({ value, done }) </span>=> <span style="color:#008000;">/*</span><span style="color:#008000;"> ... </span><span style="color:#008000;">*/</span><span style="color:#000000;">
  );</span></pre> 
   </div> 
   <p>上面代码中,<code>asyncIterator</code>是一个异步遍历器,调用<code>next</code>方法以后,返回一个 Promise 对象。因此,可以使用<code>then</code>方法指定,这个 Promise 对象的状态变为<code>resolve</code>以后的回调函数。回调函数的参数,则是一个具有<code>value</code>和<code>done</code>两个属性的对象,这个跟同步遍历器是一样的。</p> 
   <p>我们知道,一个对象的同步遍历器的接口,部署在<code>Symbol.iterator</code>属性上面。同样地,对象的异步遍历器接口,部署在<code>Symbol.asyncIterator</code>属性上面。不管是什么样的对象,只要它的<code>Symbol.asyncIterator</code>属性有值,就表示应该对它进行异步遍历。</p> 
   <p>下面是一个异步遍历器的例子。</p> 
   <div class="cnblogs_code"> 
    <pre><span style="color:#008080;"> 1</span> const asyncIterable = createAsyncIterable(['a', 'b'<span style="color:#000000;">]);
</span><span style="color:#008080;"> 2</span> const asyncIterator =<span style="color:#000000;"> asyncIterable[Symbol.asyncIterator]();
</span><span style="color:#008080;"> 3</span> 
<span style="color:#008080;"> 4</span> <span style="color:#000000;">asyncIterator
</span><span style="color:#008080;"> 5</span> <span style="color:#000000;">.next()
</span><span style="color:#008080;"> 6</span> .then(iterResult1 =><span style="color:#000000;"> {
</span><span style="color:#008080;"> 7</span>   console.log(iterResult1); <span style="color:#008000;">//</span><span style="color:#008000;"> { value: 'a', done: false }</span>
<span style="color:#008080;"> 8</span>   <span style="color:#0000ff;">return</span><span style="color:#000000;"> asyncIterator.next();
</span><span style="color:#008080;"> 9</span> <span style="color:#000000;">})
</span><span style="color:#008080;">10</span> .then(iterResult2 =><span style="color:#000000;"> {
</span><span style="color:#008080;">11</span>   console.log(iterResult2); <span style="color:#008000;">//</span><span style="color:#008000;"> { value: 'b', done: false }</span>
<span style="color:#008080;">12</span>   <span style="color:#0000ff;">return</span><span style="color:#000000;"> asyncIterator.next();
</span><span style="color:#008080;">13</span> <span style="color:#000000;">})
</span><span style="color:#008080;">14</span> .then(iterResult3 =><span style="color:#000000;"> {
</span><span style="color:#008080;">15</span>   console.log(iterResult3); <span style="color:#008000;">//</span><span style="color:#008000;"> { value: undefined, done: true }</span>
<span style="color:#008080;">16</span> });</pre> 
   </div> 
   <p>了解一下,异步遍历器不再深究。</p> 
   <h2 id="for-await---of" class="for-await---of">for await...of</h2> 
   <p>前面介绍过,<code>for...of</code>循环用于遍历同步的 Iterator 接口。新引入的<code>for await...of</code>循环,则是用于遍历异步的 Iterator 接口。</p> 
   <div class="cnblogs_code"> 
    <pre>async <span style="color:#0000ff;">function</span><span style="color:#000000;"> f() {
  </span><span style="color:#0000ff;">for</span> await (const x of createAsyncIterable(['a', 'b'<span style="color:#000000;">])) {
    console.log(x);
  }
}
</span><span style="color:#008000;">//</span><span style="color:#008000;"> a</span><span style="color:#008000;">
//</span><span style="color:#008000;"> b</span></pre> 
   </div> 
   <h2 id="异步-Generator-函数" class="异步-Generator-函数">异步 Generator 函数</h2> 
   <p> 就像 Generator 函数返回一个同步遍历器对象一样,异步 Generator 函数的作用,是返回一个异步遍历器对象。</p> 
   <h2 id="yield--语句" class="yield--语句">yield* 语句</h2> 
   <p><code>yield*</code>语句也可以跟一个异步遍历器。</p> 
   <div class="cnblogs_code"> 
    <pre>async <span style="color:#0000ff;">function</span>*<span style="color:#000000;"> gen1() {
  yield </span>'a'<span style="color:#000000;">;
  yield </span>'b'<span style="color:#000000;">;
  </span><span style="color:#0000ff;">return</span> 2<span style="color:#000000;">;
}

async </span><span style="color:#0000ff;">function</span>*<span style="color:#000000;"> gen2() {
  </span><span style="color:#008000;">//</span><span style="color:#008000;"> result 最终会等于 2</span>
  const result = yield*<span style="color:#000000;"> gen1();
}</span></pre> 
   </div> 
   <p>上面代码中,<code>gen2</code>函数里面的<code>result</code>变量,最后的值是<code>2</code>。</p> 
   <p>与同步 Generator 函数一样,<code>for await...of</code>循环会展开<code>yield*</code>。</p> 
   <p>没有最好的方法,只有最适合的方法。</p> 
  </div> 
  <p>转载于:https://www.cnblogs.com/jixiaohua/p/10674686.html</p> 
 </div> 
</div>
                            </div>
                        </div>
                    </div>
                    <!--PC和WAP自适应版-->
                    <div id="SOHUCS" sid="1292661603430375424"></div>
                    <script type="text/javascript" src="/views/front/js/chanyan.js"></script>
                    <!-- 文章页-底部 动态广告位 -->
                    <div class="youdao-fixed-ad" id="detail_ad_bottom"></div>
                </div>
                <div class="col-md-3">
                    <div class="row" id="ad">
                        <!-- 文章页-右侧1 动态广告位 -->
                        <div id="right-1" class="col-lg-12 col-md-12 col-sm-4 col-xs-4 ad">
                            <div class="youdao-fixed-ad" id="detail_ad_1"> </div>
                        </div>
                        <!-- 文章页-右侧2 动态广告位 -->
                        <div id="right-2" class="col-lg-12 col-md-12 col-sm-4 col-xs-4 ad">
                            <div class="youdao-fixed-ad" id="detail_ad_2"></div>
                        </div>
                        <!-- 文章页-右侧3 动态广告位 -->
                        <div id="right-3" class="col-lg-12 col-md-12 col-sm-4 col-xs-4 ad">
                            <div class="youdao-fixed-ad" id="detail_ad_3"></div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
    <div class="container">
        <h4 class="pt20 mb15 mt0 border-top">你可能感兴趣的:(ES6学习笔记(十六)async函数)</h4>
        <div id="paradigm-article-related">
            <div class="recommend-post mb30">
                <ul class="widget-links">
                    <li><a href="/article/1835512542735200256.htm"
                           title="C语言宏函数" target="_blank">C语言宏函数</a>
                        <span class="text-muted">南林yan</span>
<a class="tag" taget="_blank" href="/search/C%E8%AF%AD%E8%A8%80/1.htm">C语言</a><a class="tag" taget="_blank" href="/search/c%E8%AF%AD%E8%A8%80/1.htm">c语言</a>
                        <div>一、什么是宏函数?通过宏定义的函数是宏函数。如下,编译器在预处理阶段会将Add(x,y)替换为((x)*(y))#defineAdd(x,y)((x)*(y))#defineAdd(x,y)((x)*(y))intmain(){inta=10;intb=20;intd=10;intc=Add(a+d,b)*2;cout<<c<<endl;//800return0;}二、为什么要使用宏函数使用宏函数</div>
                    </li>
                    <li><a href="/article/1835511911769272320.htm"
                           title="C语言如何定义宏函数?" target="_blank">C语言如何定义宏函数?</a>
                        <span class="text-muted">小九格物</span>
<a class="tag" taget="_blank" href="/search/c%E8%AF%AD%E8%A8%80/1.htm">c语言</a>
                        <div>在C语言中,宏函数是通过预处理器定义的,它在编译之前替换代码中的宏调用。宏函数可以模拟函数的行为,但它们不是真正的函数,因为它们在编译时不会进行类型检查,也不会分配存储空间。宏函数的定义通常使用#define指令,后面跟着宏的名称和参数列表,以及宏展开后的代码。宏函数的定义方式:1.基本宏函数:这是最简单的宏函数形式,它直接定义一个表达式。#defineSQUARE(x)((x)*(x))2.带参</div>
                    </li>
                    <li><a href="/article/1835507248395284480.htm"
                           title="【一起学Rust | 设计模式】习惯语法——使用借用类型作为参数、格式化拼接字符串、构造函数" target="_blank">【一起学Rust | 设计模式】习惯语法——使用借用类型作为参数、格式化拼接字符串、构造函数</a>
                        <span class="text-muted">广龙宇</span>
<a class="tag" taget="_blank" href="/search/%E4%B8%80%E8%B5%B7%E5%AD%A6Rust/1.htm">一起学Rust</a><a class="tag" taget="_blank" href="/search/%23/1.htm">#</a><a class="tag" taget="_blank" href="/search/Rust%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/1.htm">Rust设计模式</a><a class="tag" taget="_blank" href="/search/rust/1.htm">rust</a><a class="tag" taget="_blank" href="/search/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/1.htm">设计模式</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a>
                        <div>提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档文章目录前言一、使用借用类型作为参数二、格式化拼接字符串三、使用构造函数总结前言Rust不是传统的面向对象编程语言,它的所有特性,使其独一无二。因此,学习特定于Rust的设计模式是必要的。本系列文章为作者学习《Rust设计模式》的学习笔记以及自己的见解。因此,本系列文章的结构也与此书的结构相同(后续可能会调成结构),基本上分为三个部分</div>
                    </li>
                    <li><a href="/article/1835506616682770432.htm"
                           title="每日一题——第八十四题" target="_blank">每日一题——第八十四题</a>
                        <span class="text-muted">互联网打工人no1</span>
<a class="tag" taget="_blank" href="/search/C%E8%AF%AD%E8%A8%80%E7%A8%8B%E5%BA%8F%E8%AE%BE%E8%AE%A1%E6%AF%8F%E6%97%A5%E4%B8%80%E7%BB%83/1.htm">C语言程序设计每日一练</a><a class="tag" taget="_blank" href="/search/c%E8%AF%AD%E8%A8%80/1.htm">c语言</a>
                        <div>题目:编写函数1、输入10个职工的姓名和职工号2、按照职工由大到小顺序排列,姓名顺序也随之调整3、要求输入一个职工号,用折半查找法找出该职工的姓名#define_CRT_SECURE_NO_WARNINGS#include#include#defineMAX_EMPLOYEES10typedefstruct{intid;charname[50];}Empolyee;voidinputEmploye</div>
                    </li>
                    <li><a href="/article/1835504217729626112.htm"
                           title="Python教程:一文了解使用Python处理XPath" target="_blank">Python教程:一文了解使用Python处理XPath</a>
                        <span class="text-muted">旦莫</span>
<a class="tag" taget="_blank" href="/search/Python%E8%BF%9B%E9%98%B6/1.htm">Python进阶</a><a class="tag" taget="_blank" href="/search/python/1.htm">python</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a>
                        <div>目录1.环境准备1.1安装lxml1.2验证安装2.XPath基础2.1什么是XPath?2.2XPath语法2.3示例XML文档3.使用lxml解析XML3.1解析XML文档3.2查看解析结果4.XPath查询4.1基本路径查询4.2使用属性查询4.3查询多个节点5.XPath的高级用法5.1使用逻辑运算符5.2使用函数6.实战案例6.1从网页抓取数据6.1.1安装Requests库6.1.2代</div>
                    </li>
                    <li><a href="/article/1835499615491813376.htm"
                           title="四章-32-点要素的聚合" target="_blank">四章-32-点要素的聚合</a>
                        <span class="text-muted">彩云飘过</span>

                        <div>本文基于腾讯课堂老胡的课《跟我学Openlayers--基础实例详解》做的学习笔记,使用的openlayers5.3.xapi。源码见1032.html,对应的官网示例https://openlayers.org/en/latest/examples/cluster.htmlhttps://openlayers.org/en/latest/examples/earthquake-clusters.</div>
                    </li>
                    <li><a href="/article/1835495770502033408.htm"
                           title="Day17笔记-高阶函数" target="_blank">Day17笔记-高阶函数</a>
                        <span class="text-muted">~在杰难逃~</span>
<a class="tag" taget="_blank" href="/search/Python/1.htm">Python</a><a class="tag" taget="_blank" href="/search/%E7%AC%94%E8%AE%B0/1.htm">笔记</a><a class="tag" taget="_blank" href="/search/python/1.htm">python</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a><a class="tag" taget="_blank" href="/search/pycharm/1.htm">pycharm</a><a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/1.htm">数据分析</a>
                        <div>高阶函数【重点掌握】函数的本质:函数是一个变量,函数名是一个变量名,一个函数可以作为另一个函数的参数或返回值使用如果A函数作为B函数的参数,B函数调用完成之后,会得到一个结果,则B函数被称为高阶函数常用的高阶函数:map(),reduce(),filter(),sorted()1.map()map(func,iterable),返回值是一个iterator【容器,迭代器】func:函数iterab</div>
                    </li>
                    <li><a href="/article/1835493626688401408.htm"
                           title="Python快速入门 —— 第三节:类与对象" target="_blank">Python快速入门 —— 第三节:类与对象</a>
                        <span class="text-muted">孤华暗香</span>
<a class="tag" taget="_blank" href="/search/Python%E5%BF%AB%E9%80%9F%E5%85%A5%E9%97%A8/1.htm">Python快速入门</a><a class="tag" taget="_blank" href="/search/python/1.htm">python</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a>
                        <div>第三节:类与对象目标:了解面向对象编程的基础概念,并学会如何定义类和创建对象。内容:类与对象:定义类:class关键字。类的构造函数:__init__()。类的属性和方法。对象的创建与使用。示例:classStudent:def__init__(self,name,age,major):self.name&#</div>
                    </li>
                    <li><a href="/article/1835491350896799744.htm"
                           title="赠晶晶" target="_blank">赠晶晶</a>
                        <span class="text-muted">在平凡中重新出发</span>

                        <div>逐伊衫望伊泪伊人雨中别离去莫再想莫再追莫要寸断再回味十六年六十年弹指挥间青鬓颜且浅行且珍惜待到山花烂漫时图片发自App</div>
                    </li>
                    <li><a href="/article/1835490218845761536.htm"
                           title="Python爬虫解析工具之xpath使用详解" target="_blank">Python爬虫解析工具之xpath使用详解</a>
                        <span class="text-muted">eqa11</span>
<a class="tag" taget="_blank" href="/search/python/1.htm">python</a><a class="tag" taget="_blank" href="/search/%E7%88%AC%E8%99%AB/1.htm">爬虫</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a>
                        <div>文章目录Python爬虫解析工具之xpath使用详解一、引言二、环境准备1、插件安装2、依赖库安装三、xpath语法详解1、路径表达式2、通配符3、谓语4、常用函数四、xpath在Python代码中的使用1、文档树的创建2、使用xpath表达式3、获取元素内容和属性五、总结Python爬虫解析工具之xpath使用详解一、引言在Python爬虫开发中,数据提取是一个至关重要的环节。xpath作为一门</div>
                    </li>
                    <li><a href="/article/1835489588169240576.htm"
                           title="ARM驱动学习之5 LEDS驱动" target="_blank">ARM驱动学习之5 LEDS驱动</a>
                        <span class="text-muted">JT灬新一</span>
<a class="tag" taget="_blank" href="/search/%E5%B5%8C%E5%85%A5%E5%BC%8F/1.htm">嵌入式</a><a class="tag" taget="_blank" href="/search/C/1.htm">C</a><a class="tag" taget="_blank" href="/search/%E5%BA%95%E5%B1%82/1.htm">底层</a><a class="tag" taget="_blank" href="/search/arm%E5%BC%80%E5%8F%91/1.htm">arm开发</a><a class="tag" taget="_blank" href="/search/%E5%AD%A6%E4%B9%A0/1.htm">学习</a><a class="tag" taget="_blank" href="/search/%E5%8D%95%E7%89%87%E6%9C%BA/1.htm">单片机</a>
                        <div>ARM驱动学习之5LEDS驱动知识点:•linuxGPIO申请函数和赋值函数–gpio_request–gpio_set_value•三星平台配置GPIO函数–s3c_gpio_cfgpin•GPIO配置输出模式的宏变量–S3C_GPIO_OUTPUT注意点:DRIVER_NAME和DEVICE_NAME匹配。实现步骤:1.加入需要的头文件://Linux平台的gpio头文件#include//三</div>
                    </li>
                    <li><a href="/article/1835489208152715264.htm"
                           title="Rust基础知识" target="_blank">Rust基础知识</a>
                        <span class="text-muted">GRKF15</span>
<a class="tag" taget="_blank" href="/search/rust/1.htm">rust</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a><a class="tag" taget="_blank" href="/search/%E5%90%8E%E7%AB%AF/1.htm">后端</a>
                        <div>1.Rust语言简介1.1基础语法变量声明:let关键字用于声明变量,可以指定或不指定类型,如leta=10;和letmutc=30i32;。函数定义:使用fn关键字定义函数,并指定参数类型及返回类型,如fnadd(i:i32,j:i32)->i32{i+j}。控制流:包括if、else等,控制语句后需要使用;来结束语句。1.2数据类型整数类型:i8、i16、i32、i64、i128,以及无符号的</div>
                    </li>
                    <li><a href="/article/1835475582138281984.htm"
                           title="ios GCD" target="_blank">ios GCD</a>
                        <span class="text-muted">_Waiting_</span>

                        <div>1.GCD任务和队列学习GCD之前,先来了解GCD中两个核心概念:任务和队列。任务:就是执行操作的意思,换句话说就是你在线程中执行的那段代码。在GCD中是放在block中的。执行任务有两种方式:同步执行(sync)和异步执行(async)。两者的主要区别是:是否等待队列的任务执行结束,以及是否具备开启新线程的能力。同步执行(sync):同步添加任务到指定的队列中,在添加的任务执行结束之前,会一直等</div>
                    </li>
                    <li><a href="/article/1835475216491442176.htm"
                           title="STM32中的计时与延时" target="_blank">STM32中的计时与延时</a>
                        <span class="text-muted">lupinjia</span>
<a class="tag" taget="_blank" href="/search/STM32/1.htm">STM32</a><a class="tag" taget="_blank" href="/search/stm32/1.htm">stm32</a><a class="tag" taget="_blank" href="/search/%E5%8D%95%E7%89%87%E6%9C%BA/1.htm">单片机</a>
                        <div>前言在裸机开发中,延时作为一种规定循环周期的方式经常被使用,其中尤以HAL库官方提供的HAL_Delay为甚。刚入门的小白可能会觉得既然有官方提供的延时函数,而且精度也还挺好,为什么不用呢?实际上HAL_Delay中有不少坑,而这些也只是HAL库中无数坑的其中一些。想从坑里跳出来还是得加强外设原理的学习和理解,切不可只依赖HAL库。除了延时之外,我们在开发中有时也会想要确定某段程序的耗时,这就需要</div>
                    </li>
                    <li><a href="/article/1835462484912336896.htm"
                           title="python多线程程序设计 之一" target="_blank">python多线程程序设计 之一</a>
                        <span class="text-muted">IT_Beijing_BIT</span>
<a class="tag" taget="_blank" href="/search/%23/1.htm">#</a><a class="tag" taget="_blank" href="/search/Python/1.htm">Python</a><a class="tag" taget="_blank" href="/search/%E7%A8%8B%E5%BA%8F%E8%AE%BE%E8%AE%A1%E8%AF%AD%E8%A8%80/1.htm">程序设计语言</a><a class="tag" taget="_blank" href="/search/python/1.htm">python</a>
                        <div>python多线程程序设计之一全局解释器锁线程APIsthreading.active_count()threading.current_thread()threading.excepthook(args,/)threading.get_native_id()threading.main_thread()threading.stack_size([size])线程对象成员函数构造器start/ru</div>
                    </li>
                    <li><a href="/article/1835461801232396288.htm"
                           title="现代汉语粗糙版 文学史与经典" target="_blank">现代汉语粗糙版 文学史与经典</a>
                        <span class="text-muted">学习搬运工</span>

                        <div>第十六章文学史与经典文学史的兴起在西方,虽然从亚里士多德开始,在人类的著述中已经可以找到文学史概念与写作方式的萌芽,但是,人们一般认为17世纪后期到18世纪是现代文学史写作真正开始的时期。长达百年波及整个欧洲的“古今之争”孕育出文学研究的历史意识,现代意义上的文学史观念在这场影响深远的论争中初见端倪。从18世纪晚期到19世纪初,由于席勒、弗·施莱格尔和赫尔德等人的介入,文学史研究逐渐变得复杂和成熟</div>
                    </li>
                    <li><a href="/article/1835460528621842432.htm"
                           title="语文主题教学学习笔记之87" target="_blank">语文主题教学学习笔记之87</a>
                        <span class="text-muted">东哥杂谈</span>

                        <div>“语文主题教学”学习笔记之八十七(0125)今天继续学习小学语文主题教学的实践样态。板块三:教学中体现“书艺”味道。作为四大名著之一的《水浒传》,堪称我国文学宝库之经典。对从《水浒传》中摘选的单元,教师就要了解其原生态,即评书体特点。这也要求教师要了解一些常用的评书行话术语,然后在教学时适时地加入一些,让学生体味其文本中原有的特色。学生也要尽可能地通过朗读的方式,而不单是分析讲解的方式进行学习。细</div>
                    </li>
                    <li><a href="/article/1835448619277316096.htm"
                           title="Android应用性能优化" target="_blank">Android应用性能优化</a>
                        <span class="text-muted">轻口味</span>
<a class="tag" taget="_blank" href="/search/Android/1.htm">Android</a>
                        <div>Android手机由于其本身的后台机制和硬件特点,性能上一直被诟病,所以软件开发者对软件本身的性能优化就显得尤为重要;本文将对Android开发过程中性能优化的各个方面做一个回顾与总结。Cache优化ListView缓存:ListView中有一个回收器,Item滑出界面的时候View会回收到这里,需要显示新的Item的时候,就尽量重用回收器里面的View;每次在getView函数中inflate新</div>
                    </li>
                    <li><a href="/article/1835447606348705792.htm"
                           title="C++ lambda闭包消除类成员变量" target="_blank">C++ lambda闭包消除类成员变量</a>
                        <span class="text-muted">barbyQAQ</span>
<a class="tag" taget="_blank" href="/search/c%2B%2B/1.htm">c++</a><a class="tag" taget="_blank" href="/search/c%2B%2B/1.htm">c++</a><a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/%E7%AE%97%E6%B3%95/1.htm">算法</a>
                        <div>原文链接:https://blog.csdn.net/qq_51470638/article/details/142151502一、背景在面向对象编程时,常常要添加类成员变量。然而类成员一旦多了之后,也会带来干扰。拿到一个类,一看成员变量好几十个,就问你怕不怕?二、解决思路可以借助函数式编程思想,来消除一些不必要的类成员变量。三、实例举个例子:classClassA{public:...intfu</div>
                    </li>
                    <li><a href="/article/1835443143407923200.htm"
                           title="华杉版资治通鉴【1837】崔祐甫糊弄皇帝。2023-02-20" target="_blank">华杉版资治通鉴【1837】崔祐甫糊弄皇帝。2023-02-20</a>
                        <span class="text-muted">华杉2009</span>

                        <div>7、常衮性格刚强急躁,为政苛刻琐碎,不合众心。当时,群臣早晚临丧哭哀,常衮哭得站不稳,随从有时就上前扶着他。中书舍人崔祐甫指给大家看,说:“臣子在国君灵柩前哭泣,有要人搀扶的礼节吗!”常衮听见,更加怀恨。会议讨论群臣丧服,常衮认为:“按礼制,臣为君穿丧服三年。汉文帝权衡缩短,仍然要穿三十六日。高宗以来,都遵循汉制。到了玄宗、肃宗之丧,开始只穿二十七日。如今先帝遗诏说:‘天下吏人,三日脱下丧服。’古</div>
                    </li>
                    <li><a href="/article/1835440294980579328.htm"
                           title="C++八股" target="_blank">C++八股</a>
                        <span class="text-muted">Petrichorzncu</span>
<a class="tag" taget="_blank" href="/search/%E5%85%AB%E8%82%A1%E6%80%BB%E7%BB%93/1.htm">八股总结</a><a class="tag" taget="_blank" href="/search/c%2B%2B/1.htm">c++</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a>
                        <div>这里写目录标题C++内存管理C++的构造函数,复制构造函数,和析构函数深复制与浅复制:构造函数和析构函数哪个能写成虚函数,为什么?C++数据结构内存排列结构体和类占用的内存:==虚函数和虚表的原理==虚函数虚表(Vtable)虚函数和虚表的实现细节==内存泄漏==指针的工作原理函数的传值和传址new和delete与malloc和freeC++内存区域划分C++11新特性C++常见新特性==智能指针</div>
                    </li>
                    <li><a href="/article/1835439069815992320.htm"
                           title="《结婚十六年感赋》" target="_blank">《结婚十六年感赋》</a>
                        <span class="text-muted">灵隐济癫</span>

                        <div>弹指光阴逝,成婚十六年。相亲酬旧约,作伴惜良缘。不羡鸳鸯侣,当如鸾凤仙。齐眉情缱绻,携手意缠绵。</div>
                    </li>
                    <li><a href="/article/1835436642270277632.htm"
                           title="【Python搞定车载自动化测试】——Python实现车载以太网DoIP刷写(含Python源码)" target="_blank">【Python搞定车载自动化测试】——Python实现车载以太网DoIP刷写(含Python源码)</a>
                        <span class="text-muted">疯狂的机器人</span>
<a class="tag" taget="_blank" href="/search/Python%E6%90%9E%E5%AE%9A%E8%BD%A6%E8%BD%BD%E8%87%AA%E5%8A%A8%E5%8C%96/1.htm">Python搞定车载自动化</a><a class="tag" taget="_blank" href="/search/python/1.htm">python</a><a class="tag" taget="_blank" href="/search/DoIP/1.htm">DoIP</a><a class="tag" taget="_blank" href="/search/UDS/1.htm">UDS</a><a class="tag" taget="_blank" href="/search/ISO/1.htm">ISO</a><a class="tag" taget="_blank" href="/search/14229/1.htm">14229</a><a class="tag" taget="_blank" href="/search/1SO/1.htm">1SO</a><a class="tag" taget="_blank" href="/search/13400/1.htm">13400</a><a class="tag" taget="_blank" href="/search/Bootloader/1.htm">Bootloader</a><a class="tag" taget="_blank" href="/search/tcp%2Fip/1.htm">tcp/ip</a>
                        <div>系列文章目录【Python搞定车载自动化测试】系列文章目录汇总文章目录系列文章目录前言一、环境搭建1.软件环境2.硬件环境二、目录结构三、源码展示1.DoIP诊断基础函数方法2.DoIP诊断业务函数方法3.27服务安全解锁4.DoIP自动化刷写四、测试日志1.测试日志五、完整源码链接前言随着智能电动汽车行业的发展,汽车=智能终端+四个轮子,各家车企都推出了各自的OTA升级方案,本章节主要介绍如何使</div>
                    </li>
                    <li><a href="/article/1835435758844997632.htm"
                           title="【2022 CCF 非专业级别软件能力认证第一轮(CSP-J1)入门级 C++语言试题及解析】" target="_blank">【2022 CCF 非专业级别软件能力认证第一轮(CSP-J1)入门级 C++语言试题及解析】</a>
                        <span class="text-muted">汉子萌萌哒</span>
<a class="tag" taget="_blank" href="/search/CCF/1.htm">CCF</a><a class="tag" taget="_blank" href="/search/noi/1.htm">noi</a><a class="tag" taget="_blank" href="/search/%E7%AE%97%E6%B3%95/1.htm">算法</a><a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/1.htm">数据结构</a><a class="tag" taget="_blank" href="/search/c%2B%2B/1.htm">c++</a>
                        <div>一、单项选择题(共15题,每题2分,共计30分;每题有且仅有一个正确选项)1.以下哪种功能没有涉及C++语言的面向对象特性支持:()。A.C++中调用printf函数B.C++中调用用户定义的类成员函数C.C++中构造一个class或structD.C++中构造来源于同一基类的多个派生类题目解析【解析】正确答案:AC++基础知识,面向对象和类有关,类又涉及父类、子类、继承、派生等关系,printf</div>
                    </li>
                    <li><a href="/article/1835434623782449152.htm"
                           title="matlab delsat = setdiff(1:69,unique(Eph(30,:))); 语句含义" target="_blank">matlab delsat = setdiff(1:69,unique(Eph(30,:))); 语句含义</a>
                        <span class="text-muted">黄卷青灯77</span>
<a class="tag" taget="_blank" href="/search/matlab/1.htm">matlab</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a><a class="tag" taget="_blank" href="/search/setdiff/1.htm">setdiff</a>
                        <div>这行MATLAB代码用于计算在范围1:69中不包含在Eph矩阵第30行的唯一值集合中的所有元素。具体解释如下:delsat=setdiff(1:69,unique(Eph(30,:)));解释Eph(30,:)Eph(30,:)提取矩阵Eph的第30行的所有列元素。这是一个行向量,包含了第30行的所有值。unique(Eph(30,:))unique函数返回Eph(30,:)中的唯一元素。这意味着</div>
                    </li>
                    <li><a href="/article/1835432106029838336.htm"
                           title="【RabbitMQ 项目】服务端:数据管理模块之绑定管理" target="_blank">【RabbitMQ 项目】服务端:数据管理模块之绑定管理</a>
                        <span class="text-muted">月夜星辉雪</span>
<a class="tag" taget="_blank" href="/search/rabbitmq/1.htm">rabbitmq</a><a class="tag" taget="_blank" href="/search/%E5%88%86%E5%B8%83%E5%BC%8F/1.htm">分布式</a>
                        <div>文章目录一.编写思路二.代码实践一.编写思路定义绑定信息类交换机名称队列名称绑定关键字:交换机的路由交换算法中会用到没有是否持久化的标志,因为绑定是否持久化取决于交换机和队列是否持久化,只有它们都持久化时绑定才需要持久化。绑定就好像一根绳子,两端连接着交换机和队列,当一方不存在,它就没有存在的必要了定义绑定持久化类构造函数:如果数据库文件不存在则创建,打开数据库,创建binding_table插入</div>
                    </li>
                    <li><a href="/article/1835429927567060992.htm"
                           title="《转介绍方法论》学习笔记" target="_blank">《转介绍方法论》学习笔记</a>
                        <span class="text-muted">小可乐的妈妈</span>

                        <div>一、高效转介绍的流程:价值观---执行----方案一)转介绍发生的背景:1、对象:谁向谁转介绍?全员营销,人人参与。①员工的激励政策、客户的转介绍诱因制作客户画像:a信任;支付能力;意愿度;便利度(根据家长具备四个特征的个数分为四类)B性格分类C职业分类D年龄性别②执行:套路,策略,方法,流程2、诱因:为什么要转介绍?认同信任;多方共赢;传递美好;零风险承诺打动人心,超越期待。选择做教育,就是选择</div>
                    </li>
                    <li><a href="/article/1835429581205630976.htm"
                           title="JAVA学习笔记之23种设计模式学习" target="_blank">JAVA学习笔记之23种设计模式学习</a>
                        <span class="text-muted">victorfreedom</span>
<a class="tag" taget="_blank" href="/search/Java%E6%8A%80%E6%9C%AF/1.htm">Java技术</a><a class="tag" taget="_blank" href="/search/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/1.htm">设计模式</a><a class="tag" taget="_blank" href="/search/android/1.htm">android</a><a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/%E5%B8%B8%E7%94%A8%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/1.htm">常用设计模式</a>
                        <div>博主最近买了《设计模式》这本书来学习,无奈这本书是以C++语言为基础进行说明,整个学习流程下来效率不是很高,虽然有的设计模式通俗易懂,但感觉还是没有充分的掌握了所有的设计模式。于是博主百度了一番,发现有大神写过了这方面的问题,于是博主迅速拿来学习。一、设计模式的分类总体来说设计模式分为三大类:创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。结构型模式,共七种:适配器</div>
                    </li>
                    <li><a href="/article/1835429075590672384.htm"
                           title="粒子群优化 (PSO) 在三维正弦波函数中的应用" target="_blank">粒子群优化 (PSO) 在三维正弦波函数中的应用</a>
                        <span class="text-muted">subject625Ruben</span>
<a class="tag" taget="_blank" href="/search/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/1.htm">机器学习</a><a class="tag" taget="_blank" href="/search/%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD/1.htm">人工智能</a><a class="tag" taget="_blank" href="/search/matlab/1.htm">matlab</a><a class="tag" taget="_blank" href="/search/%E7%AE%97%E6%B3%95/1.htm">算法</a>
                        <div>在这篇博客中,我们将展示如何使用粒子群优化(PSO)算法求解三维正弦波函数,并通过增加正弦波扰动,使优化过程更加复杂和有趣。本文将介绍目标函数的定义、PSO参数设置以及算法执行的详细过程,并展示搜索空间中的动态过程和收敛曲线。1.目标函数定义我们使用的目标函数是一个三维正弦波函数,定义如下:objectiveFunc=@(x)sin(sqrt(x(1).^2+x(2).^2))+0.5*sin(5</div>
                    </li>
                    <li><a href="/article/1835419870565593088.htm"
                           title="c++ 内存处理函数" target="_blank">c++ 内存处理函数</a>
                        <span class="text-muted">heeheeai</span>
<a class="tag" taget="_blank" href="/search/c%2B%2B/1.htm">c++</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a>
                        <div>在C语言的头文件中,memcpy和memmove函数都用于复制内存块,但它们在处理内存重叠方面存在关键区别:内存重叠:memcpy函数不保证在源内存和目标内存区域重叠时能够正确复制数据。如果内存区域重叠,memcpy的行为是未定义的,可能会导致数据损坏或程序崩溃。memmove函数能够安全地处理源内存和目标内存区域重叠的情况。它会确保在复制过程中不会覆盖尚未复制的数据,从而保证数据的完整性。效率:</div>
                    </li>
                                <li><a href="/article/84.htm"
                                       title="继之前的线程循环加到窗口中运行" target="_blank">继之前的线程循环加到窗口中运行</a>
                                    <span class="text-muted">3213213333332132</span>
<a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/thread/1.htm">thread</a><a class="tag" taget="_blank" href="/search/JFrame/1.htm">JFrame</a><a class="tag" taget="_blank" href="/search/JPanel/1.htm">JPanel</a>
                                    <div>之前写了有关java线程的循环执行和结束,因为想制作成exe文件,想把执行的效果加到窗口上,所以就结合了JFrame和JPanel写了这个程序,这里直接贴出代码,在窗口上运行的效果下面有附图。 
 

package thread;

import java.awt.Graphics;
import java.text.SimpleDateFormat;
import java.util</div>
                                </li>
                                <li><a href="/article/211.htm"
                                       title="linux 常用命令" target="_blank">linux 常用命令</a>
                                    <span class="text-muted">BlueSkator</span>
<a class="tag" taget="_blank" href="/search/linux/1.htm">linux</a><a class="tag" taget="_blank" href="/search/%E5%91%BD%E4%BB%A4/1.htm">命令</a>
                                    <div>1.grep 
相信这个命令可以说是大家最常用的命令之一了。尤其是查询生产环境的日志,这个命令绝对是必不可少的。 
但之前总是习惯于使用 (grep -n 关键字 文件名 )查出关键字以及该关键字所在的行数,然后再用 (sed -n  '100,200p' 文件名),去查出该关键字之后的日志内容。 
但其实还有更简便的办法,就是用(grep  -B n、-A n、-C n 关键</div>
                                </li>
                                <li><a href="/article/338.htm"
                                       title="php heredoc原文档和nowdoc语法" target="_blank">php heredoc原文档和nowdoc语法</a>
                                    <span class="text-muted">dcj3sjt126com</span>
<a class="tag" taget="_blank" href="/search/PHP/1.htm">PHP</a><a class="tag" taget="_blank" href="/search/heredoc/1.htm">heredoc</a><a class="tag" taget="_blank" href="/search/nowdoc/1.htm">nowdoc</a>
                                    <div><!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>Current To-Do List</title>
</head>
<body>
<?</div>
                                </li>
                                <li><a href="/article/465.htm"
                                       title="overflow的属性" target="_blank">overflow的属性</a>
                                    <span class="text-muted">周华华</span>
<a class="tag" taget="_blank" href="/search/JavaScript/1.htm">JavaScript</a>
                                    <div><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
<html xmlns="http://www.w3.org/1999/xhtml&q</div>
                                </li>
                                <li><a href="/article/592.htm"
                                       title="《我所了解的Java》——总体目录" target="_blank">《我所了解的Java》——总体目录</a>
                                    <span class="text-muted">g21121</span>
<a class="tag" taget="_blank" href="/search/java/1.htm">java</a>
                                    <div>        准备用一年左右时间写一个系列的文章《我所了解的Java》,目录及内容会不断完善及调整。 
        在编写相关内容时难免出现笔误、代码无法执行、名词理解错误等,请大家及时指出,我会第一时间更正。 
   &n</div>
                                </li>
                                <li><a href="/article/719.htm"
                                       title="[简单]docx4j常用方法小结" target="_blank">[简单]docx4j常用方法小结</a>
                                    <span class="text-muted">53873039oycg</span>
<a class="tag" taget="_blank" href="/search/docx/1.htm">docx</a>
                                    <div>        本代码基于docx4j-3.2.0,在office word 2007上测试通过。代码如下: 
         
import java.io.File;
import java.io.FileInputStream;
import ja</div>
                                </li>
                                <li><a href="/article/846.htm"
                                       title="Spring配置学习" target="_blank">Spring配置学习</a>
                                    <span class="text-muted">云端月影</span>
<a class="tag" taget="_blank" href="/search/spring%E9%85%8D%E7%BD%AE/1.htm">spring配置</a>
                                    <div> 
首先来看一个标准的Spring配置文件 applicationContext.xml 
 
<?xml version="1.0" encoding="UTF-8"?> 
<beans xmlns="http://www.springframework.org/schema/beans" 
 xmlns:xsi=&q</div>
                                </li>
                                <li><a href="/article/973.htm"
                                       title="Java新手入门的30个基本概念三" target="_blank">Java新手入门的30个基本概念三</a>
                                    <span class="text-muted">aijuans</span>
<a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/%E6%96%B0%E6%89%8B/1.htm">新手</a><a class="tag" taget="_blank" href="/search/java+%E5%85%A5%E9%97%A8/1.htm">java 入门</a>
                                    <div>17.Java中的每一个类都是从Object类扩展而来的。  18.object类中的equal和toString方法。  equal用于测试一个对象是否同另一个对象相等。  toString返回一个代表该对象的字符串,几乎每一个类都会重载该方法,以便返回当前状态的正确表示.(toString 方法是一个很重要的方法)   19.通用编程:任何类类型的所有值都可以同object类性的变量来代替。 </div>
                                </li>
                                <li><a href="/article/1100.htm"
                                       title="《2008 IBM Rational 软件开发高峰论坛会议》小记" target="_blank">《2008 IBM Rational 软件开发高峰论坛会议》小记</a>
                                    <span class="text-muted">antonyup_2006</span>
<a class="tag" taget="_blank" href="/search/%E8%BD%AF%E4%BB%B6%E6%B5%8B%E8%AF%95/1.htm">软件测试</a><a class="tag" taget="_blank" href="/search/%E6%95%8F%E6%8D%B7%E5%BC%80%E5%8F%91/1.htm">敏捷开发</a><a class="tag" taget="_blank" href="/search/%E9%A1%B9%E7%9B%AE%E7%AE%A1%E7%90%86/1.htm">项目管理</a><a class="tag" taget="_blank" href="/search/IBM/1.htm">IBM</a><a class="tag" taget="_blank" href="/search/%E6%B4%BB%E5%8A%A8/1.htm">活动</a>
                                    <div>我一直想写些总结,用于交流和备忘,然都没提笔,今以一篇参加活动的感受小记开个头,呵呵! 
 
其实参加《2008 IBM Rational 软件开发高峰论坛会议》是9月4号,那天刚好调休.但接着项目颇为忙,所以今天在中秋佳节的假期里整理了下. 
 
参加这次活动是一个朋友给的一个邀请书,才知道有这样的一个活动,虽然现在项目暂时没用到IBM的解决方案,但觉的参与这样一个活动可以拓宽下视野和相关知识.</div>
                                </li>
                                <li><a href="/article/1227.htm"
                                       title="PL/SQL的过程编程,异常,声明变量,PL/SQL块" target="_blank">PL/SQL的过程编程,异常,声明变量,PL/SQL块</a>
                                    <span class="text-muted">百合不是茶</span>
<a class="tag" taget="_blank" href="/search/PL%2FSQL%E7%9A%84%E8%BF%87%E7%A8%8B%E7%BC%96%E7%A8%8B/1.htm">PL/SQL的过程编程</a><a class="tag" taget="_blank" href="/search/%E5%BC%82%E5%B8%B8/1.htm">异常</a><a class="tag" taget="_blank" href="/search/PL%2FSQL%E5%9D%97/1.htm">PL/SQL块</a><a class="tag" taget="_blank" href="/search/%E5%A3%B0%E6%98%8E%E5%8F%98%E9%87%8F/1.htm">声明变量</a>
                                    <div>PL/SQL; 
   
   过程;

    符号;

     变量;

     PL/SQL块;

     输出;

     异常;
 
  
  
PL/SQL 是过程语言(Procedural Language)与结构化查询语言(SQL)结合而成的编程语言PL/SQL 是对 SQL 的扩展,sql的执行时每次都要写操作</div>
                                </li>
                                <li><a href="/article/1354.htm"
                                       title="Mockito(三)--完整功能介绍" target="_blank">Mockito(三)--完整功能介绍</a>
                                    <span class="text-muted">bijian1013</span>
<a class="tag" taget="_blank" href="/search/%E6%8C%81%E7%BB%AD%E9%9B%86%E6%88%90/1.htm">持续集成</a><a class="tag" taget="_blank" href="/search/mockito/1.htm">mockito</a><a class="tag" taget="_blank" href="/search/%E5%8D%95%E5%85%83%E6%B5%8B%E8%AF%95/1.htm">单元测试</a>
                                    <div>        mockito官网:http://code.google.com/p/mockito/,打开documentation可以看到官方最新的文档资料。 
一.使用mockito验证行为 
//首先要import Mockito
import static org.mockito.Mockito.*;

//mo</div>
                                </li>
                                <li><a href="/article/1481.htm"
                                       title="精通Oracle10编程SQL(8)使用复合数据类型" target="_blank">精通Oracle10编程SQL(8)使用复合数据类型</a>
                                    <span class="text-muted">bijian1013</span>
<a class="tag" taget="_blank" href="/search/oracle/1.htm">oracle</a><a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE%E5%BA%93/1.htm">数据库</a><a class="tag" taget="_blank" href="/search/plsql/1.htm">plsql</a>
                                    <div>/*
 *使用复合数据类型
 */

--PL/SQL记录
--定义PL/SQL记录
--自定义PL/SQL记录
DECLARE
  TYPE emp_record_type IS RECORD(
     name emp.ename%TYPE,
     salary emp.sal%TYPE,
     dno emp.deptno%TYPE
  );
  emp_</div>
                                </li>
                                <li><a href="/article/1608.htm"
                                       title="【Linux常用命令一】grep命令" target="_blank">【Linux常用命令一】grep命令</a>
                                    <span class="text-muted">bit1129</span>
<a class="tag" taget="_blank" href="/search/Linux%E5%B8%B8%E7%94%A8%E5%91%BD%E4%BB%A4/1.htm">Linux常用命令</a>
                                    <div>grep命令格式 
  
grep [option] pattern [file-list] 
  
  
grep命令用于在指定的文件(一个或者多个,file-list)中查找包含模式串(pattern)的行,[option]用于控制grep命令的查找方式。 
  
pattern可以是普通字符串,也可以是正则表达式,当查找的字符串包含正则表达式字符或者特</div>
                                </li>
                                <li><a href="/article/1735.htm"
                                       title="mybatis3入门学习笔记" target="_blank">mybatis3入门学习笔记</a>
                                    <span class="text-muted">白糖_</span>
<a class="tag" taget="_blank" href="/search/sql/1.htm">sql</a><a class="tag" taget="_blank" href="/search/ibatis/1.htm">ibatis</a><a class="tag" taget="_blank" href="/search/qq/1.htm">qq</a><a class="tag" taget="_blank" href="/search/jdbc/1.htm">jdbc</a><a class="tag" taget="_blank" href="/search/%E9%85%8D%E7%BD%AE%E7%AE%A1%E7%90%86/1.htm">配置管理</a>
                                    <div>MyBatis 的前身就是iBatis,是一个数据持久层(ORM)框架。  MyBatis 是支持普通 SQL 查询,存储过程和高级映射的优秀持久层框架。MyBatis对JDBC进行了一次很浅的封装。 
  
以前也学过iBatis,因为MyBatis是iBatis的升级版本,最初以为改动应该不大,实际结果是MyBatis对配置文件进行了一些大的改动,使整个框架更加方便人性化。</div>
                                </li>
                                <li><a href="/article/1862.htm"
                                       title="Linux 命令神器:lsof 入门" target="_blank">Linux 命令神器:lsof 入门</a>
                                    <span class="text-muted">ronin47</span>
<a class="tag" taget="_blank" href="/search/lsof/1.htm">lsof</a>
                                    <div>       
lsof是系统管理/安全的尤伯工具。我大多数时候用它来从系统获得与网络连接相关的信息,但那只是这个强大而又鲜为人知的应用的第一步。将这个工具称之为lsof真实名副其实,因为它是指“列出打开文件(lists openfiles)”。而有一点要切记,在Unix中一切(包括网络套接口)都是文件。 
有趣的是,lsof也是有着最多</div>
                                </li>
                                <li><a href="/article/1989.htm"
                                       title="java实现两个大数相加,可能存在溢出。" target="_blank">java实现两个大数相加,可能存在溢出。</a>
                                    <span class="text-muted">bylijinnan</span>
<a class="tag" taget="_blank" href="/search/java%E5%AE%9E%E7%8E%B0/1.htm">java实现</a>
                                    <div>
import java.math.BigInteger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


public class BigIntegerAddition {

	/**
	 * 题目:java实现两个大数相加,可能存在溢出。
	 * 如123456789 + 987654321</div>
                                </li>
                                <li><a href="/article/2116.htm"
                                       title="Kettle学习资料分享,附大神用Kettle的一套流程完成对整个数据库迁移方法" target="_blank">Kettle学习资料分享,附大神用Kettle的一套流程完成对整个数据库迁移方法</a>
                                    <span class="text-muted">Kai_Ge</span>
<a class="tag" taget="_blank" href="/search/Kettle/1.htm">Kettle</a>
                                    <div>Kettle学习资料分享 
  
Kettle 3.2 使用说明书 
目录 
概述..........................................................................................................................................7 
1.Kettle 资源库管</div>
                                </li>
                                <li><a href="/article/2243.htm"
                                       title="[货币与金融]钢之炼金术士" target="_blank">[货币与金融]钢之炼金术士</a>
                                    <span class="text-muted">comsci</span>
<a class="tag" taget="_blank" href="/search/%E9%87%91%E8%9E%8D/1.htm">金融</a>
                                    <div> 
 
       自古以来,都有一些人在从事炼金术的工作.........但是很少有成功的 
 
       那么随着人类在理论物理和工程物理上面取得的一些突破性进展...... 
 
       炼金术这个古老</div>
                                </li>
                                <li><a href="/article/2370.htm"
                                       title="Toast原来也可以多样化" target="_blank">Toast原来也可以多样化</a>
                                    <span class="text-muted">dai_lm</span>
<a class="tag" taget="_blank" href="/search/android/1.htm">android</a><a class="tag" taget="_blank" href="/search/toast/1.htm">toast</a>
                                    <div>Style 1: 默认 
 

Toast def = Toast.makeText(this, "default", Toast.LENGTH_SHORT);
def.show();
 
Style 2: 顶部显示 
 

Toast top = Toast.makeText(this, "top", Toast.LENGTH_SHORT);
t</div>
                                </li>
                                <li><a href="/article/2497.htm"
                                       title="java数据计算的几种解决方法3" target="_blank">java数据计算的几种解决方法3</a>
                                    <span class="text-muted">datamachine</span>
<a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/hadoop/1.htm">hadoop</a><a class="tag" taget="_blank" href="/search/ibatis/1.htm">ibatis</a><a class="tag" taget="_blank" href="/search/r-langue/1.htm">r-langue</a><a class="tag" taget="_blank" href="/search/r/1.htm">r</a>
                                    <div>4、iBatis 
    简单敏捷因此强大的数据计算层。和Hibernate不同,它鼓励写SQL,所以学习成本最低。同时它用最小的代价实现了计算脚本和JAVA代码的解耦,只用20%的代价就实现了hibernate 80%的功能,没实现的20%是计算脚本和数据库的解耦。 
    复杂计算环境是它的弱项,比如:分布式计算、复杂计算、非数据</div>
                                </li>
                                <li><a href="/article/2624.htm"
                                       title="向网页中插入透明Flash的方法和技巧" target="_blank">向网页中插入透明Flash的方法和技巧</a>
                                    <span class="text-muted">dcj3sjt126com</span>
<a class="tag" taget="_blank" href="/search/html/1.htm">html</a><a class="tag" taget="_blank" href="/search/Web/1.htm">Web</a><a class="tag" taget="_blank" href="/search/Flash/1.htm">Flash</a>
                                    <div>将 
Flash 作品插入网页的时候,我们有时候会需要将它设为透明,有时候我们需要在Flash的背面插入一些漂亮的图片,搭配出漂亮的效果……下面我们介绍一些将Flash插入网页中的一些透明的设置技巧。  
  一、Swf透明、无坐标控制  首先教大家最简单的插入Flash的代码,透明,无坐标控制:   注意wmode="transparent"是控制Flash是否透明</div>
                                </li>
                                <li><a href="/article/2751.htm"
                                       title="ios UICollectionView的使用" target="_blank">ios UICollectionView的使用</a>
                                    <span class="text-muted">dcj3sjt126com</span>

                                    <div>UICollectionView的使用有两种方法,一种是继承UICollectionViewController,这个Controller会自带一个UICollectionView;另外一种是作为一个视图放在普通的UIViewController里面。 
个人更喜欢第二种。下面采用第二种方式简单介绍一下UICollectionView的使用。 
1.UIViewController实现委托,代码如</div>
                                </li>
                                <li><a href="/article/2878.htm"
                                       title="Eos平台java公共逻辑" target="_blank">Eos平台java公共逻辑</a>
                                    <span class="text-muted">蕃薯耀</span>
<a class="tag" taget="_blank" href="/search/Eos%E5%B9%B3%E5%8F%B0java%E5%85%AC%E5%85%B1%E9%80%BB%E8%BE%91/1.htm">Eos平台java公共逻辑</a><a class="tag" taget="_blank" href="/search/Eos%E5%B9%B3%E5%8F%B0/1.htm">Eos平台</a><a class="tag" taget="_blank" href="/search/java%E5%85%AC%E5%85%B1%E9%80%BB%E8%BE%91/1.htm">java公共逻辑</a>
                                    <div> Eos平台java公共逻辑 
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 
蕃薯耀 2015年6月1日 17:20:4</div>
                                </li>
                                <li><a href="/article/3005.htm"
                                       title="SpringMVC4零配置--Web上下文配置【MvcConfig】" target="_blank">SpringMVC4零配置--Web上下文配置【MvcConfig】</a>
                                    <span class="text-muted">hanqunfeng</span>
<a class="tag" taget="_blank" href="/search/springmvc4/1.htm">springmvc4</a>
                                    <div>与SpringSecurity的配置类似,spring同样为我们提供了一个实现类WebMvcConfigurationSupport和一个注解@EnableWebMvc以帮助我们减少bean的声明。 
  
applicationContext-MvcConfig.xml 
<!-- 启用注解,并定义组件查找规则 ,mvc层只负责扫描@Controller -->
	<</div>
                                </li>
                                <li><a href="/article/3132.htm"
                                       title="解决ie和其他浏览器poi下载excel文件名乱码" target="_blank">解决ie和其他浏览器poi下载excel文件名乱码</a>
                                    <span class="text-muted">jackyrong</span>
<a class="tag" taget="_blank" href="/search/Excel/1.htm">Excel</a>
                                    <div>   使用poi,做传统的excel导出,然后想在浏览器中,让用户选择另存为,保存用户下载的xls文件,这个时候,可能的是在ie下出现乱码(ie,9,10,11),但在firefox,chrome下没乱码, 
 
因此必须综合判断,编写一个工具类: 
 
 
     

/**
     * 
     * @Title: pro</div>
                                </li>
                                <li><a href="/article/3259.htm"
                                       title="挥洒泪水的青春" target="_blank">挥洒泪水的青春</a>
                                    <span class="text-muted">lampcy</span>
<a class="tag" taget="_blank" href="/search/%E7%BC%96%E7%A8%8B/1.htm">编程</a><a class="tag" taget="_blank" href="/search/%E7%94%9F%E6%B4%BB/1.htm">生活</a><a class="tag" taget="_blank" href="/search/%E7%A8%8B%E5%BA%8F%E5%91%98/1.htm">程序员</a>
                                    <div>2015年2月28日,我辞职了,离开了相处一年的触控,转过身--挥洒掉泪水,毅然来到了兄弟连,背负着许多的不解、质疑——”你一个零基础、脑子又不聪明的人,还敢跨行业,选择Unity3D?“,”真是不自量力••••••“,”真是初生牛犊不怕虎•••••“,••••••我只是淡淡一笑,拎着行李----坐上了通向挥洒泪水的青春之地——兄弟连! 
这就是我青春的分割线,不后悔,只会去用泪水浇灌——已经来到</div>
                                </li>
                                <li><a href="/article/3386.htm"
                                       title="稳增长之中国股市两点意见-----严控做空,建立涨跌停版停牌重组机制" target="_blank">稳增长之中国股市两点意见-----严控做空,建立涨跌停版停牌重组机制</a>
                                    <span class="text-muted">nannan408</span>

                                    <div>   对于股市,我们国家的监管还是有点拼的,但始终拼不过飞流直下的恐慌,为什么呢? 
   笔者首先支持股市的监管。对于股市越管越荡的现象,笔者认为首先是做空力量超过了股市自身的升力,并且对于跌停停牌重组的快速反应还没建立好,上市公司对于股价下跌没有很好的利好支撑。 
   我们来看美国和香港是怎么应对股灾的。美国是靠禁止重要股票做空,在</div>
                                </li>
                                <li><a href="/article/3513.htm"
                                       title="动态设置iframe高度(iframe高度自适应)" target="_blank">动态设置iframe高度(iframe高度自适应)</a>
                                    <span class="text-muted">Rainbow702</span>
<a class="tag" taget="_blank" href="/search/JavaScript/1.htm">JavaScript</a><a class="tag" taget="_blank" href="/search/iframe/1.htm">iframe</a><a class="tag" taget="_blank" href="/search/contentDocument/1.htm">contentDocument</a><a class="tag" taget="_blank" href="/search/%E9%AB%98%E5%BA%A6%E8%87%AA%E9%80%82%E5%BA%94/1.htm">高度自适应</a><a class="tag" taget="_blank" href="/search/%E5%B1%80%E9%83%A8%E5%88%B7%E6%96%B0/1.htm">局部刷新</a>
                                    <div>如果需要对画面中的部分区域作局部刷新,大家可能都会想到使用ajax。 
但有些情况下,须使用在页面中嵌入一个iframe来作局部刷新。 
对于使用iframe的情况,发现有一个问题,就是iframe中的页面的高度可能会很高,但是外面页面并不会被iframe内部页面给撑开,如下面的结构: 
<div id="content">
    <div id=&quo</div>
                                </li>
                                <li><a href="/article/3640.htm"
                                       title="用Rapael做图表" target="_blank">用Rapael做图表</a>
                                    <span class="text-muted">tntxia</span>
<a class="tag" taget="_blank" href="/search/rap/1.htm">rap</a>
                                    <div>function drawReport(paper,attr,data){ 
     
    var width = attr.width; 
    var height = attr.height; 
     
    var max = 0; 
  &nbs</div>
                                </li>
                                <li><a href="/article/3767.htm"
                                       title="HTML5 bootstrap2网页兼容(支持IE10以下)" target="_blank">HTML5 bootstrap2网页兼容(支持IE10以下)</a>
                                    <span class="text-muted">xiaoluode</span>
<a class="tag" taget="_blank" href="/search/html5/1.htm">html5</a><a class="tag" taget="_blank" href="/search/bootstrap/1.htm">bootstrap</a>
                                    <div><!DOCTYPE html>
<html>
<head lang="zh-CN">
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge"></div>
                                </li>
                </ul>
            </div>
        </div>
    </div>

<div>
    <div class="container">
        <div class="indexes">
            <strong>按字母分类:</strong>
            <a href="/tags/A/1.htm" target="_blank">A</a><a href="/tags/B/1.htm" target="_blank">B</a><a href="/tags/C/1.htm" target="_blank">C</a><a
                href="/tags/D/1.htm" target="_blank">D</a><a href="/tags/E/1.htm" target="_blank">E</a><a href="/tags/F/1.htm" target="_blank">F</a><a
                href="/tags/G/1.htm" target="_blank">G</a><a href="/tags/H/1.htm" target="_blank">H</a><a href="/tags/I/1.htm" target="_blank">I</a><a
                href="/tags/J/1.htm" target="_blank">J</a><a href="/tags/K/1.htm" target="_blank">K</a><a href="/tags/L/1.htm" target="_blank">L</a><a
                href="/tags/M/1.htm" target="_blank">M</a><a href="/tags/N/1.htm" target="_blank">N</a><a href="/tags/O/1.htm" target="_blank">O</a><a
                href="/tags/P/1.htm" target="_blank">P</a><a href="/tags/Q/1.htm" target="_blank">Q</a><a href="/tags/R/1.htm" target="_blank">R</a><a
                href="/tags/S/1.htm" target="_blank">S</a><a href="/tags/T/1.htm" target="_blank">T</a><a href="/tags/U/1.htm" target="_blank">U</a><a
                href="/tags/V/1.htm" target="_blank">V</a><a href="/tags/W/1.htm" target="_blank">W</a><a href="/tags/X/1.htm" target="_blank">X</a><a
                href="/tags/Y/1.htm" target="_blank">Y</a><a href="/tags/Z/1.htm" target="_blank">Z</a><a href="/tags/0/1.htm" target="_blank">其他</a>
        </div>
    </div>
</div>
<footer id="footer" class="mb30 mt30">
    <div class="container">
        <div class="footBglm">
            <a target="_blank" href="/">首页</a> -
            <a target="_blank" href="/custom/about.htm">关于我们</a> -
            <a target="_blank" href="/search/Java/1.htm">站内搜索</a> -
            <a target="_blank" href="/sitemap.txt">Sitemap</a> -
            <a target="_blank" href="/custom/delete.htm">侵权投诉</a>
        </div>
        <div class="copyright">版权所有 IT知识库 CopyRight © 2000-2050 E-COM-NET.COM , All Rights Reserved.
<!--            <a href="https://beian.miit.gov.cn/" rel="nofollow" target="_blank">京ICP备09083238号</a><br>-->
        </div>
    </div>
</footer>
<!-- 代码高亮 -->
<script type="text/javascript" src="/static/syntaxhighlighter/scripts/shCore.js"></script>
<script type="text/javascript" src="/static/syntaxhighlighter/scripts/shLegacy.js"></script>
<script type="text/javascript" src="/static/syntaxhighlighter/scripts/shAutoloader.js"></script>
<link type="text/css" rel="stylesheet" href="/static/syntaxhighlighter/styles/shCoreDefault.css"/>
<script type="text/javascript" src="/static/syntaxhighlighter/src/my_start_1.js"></script>





</body>

</html>