ES6——异步操作

async 函数

ES2017 标准引入了 async 函数,使得异步操作变得更加方便。
async 函数是什么?一句话,它就是 Generator 函数的语法糖。
前文有一个 Generator 函数,依次读取两个文件。

const fs = require('fs');

const readFile = function (fileName) {
  return new Promise(function (resolve, reject) {
    fs.readFile(fileName, function(error, data) {
      if (error) return reject(error);
      resolve(data);
    });
  });
};

const gen = function* () {
  const f1 = yield readFile('/etc/fstab');
  const f2 = yield readFile('/etc/shells');
  console.log(f1.toString());
  console.log(f2.toString());
};

上面代码的函数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命令的语法糖。

基本用法

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对象。

下面是另一个例子,指定多少毫秒后输出一个值。

function timeout(ms) {
  return new Promise((resolve) => {
    setTimeout(resolve, ms);
  });
}

async function asyncPrint(value, ms) {
  await timeout(ms);
  console.log(value);
}

asyncPrint('hello world', 50);

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

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

async function timeout(ms) {
  await new Promise((resolve) => {
    setTimeout(resolve, ms);
  });
}

async function asyncPrint(value, ms) {
  await timeout(ms);
  console.log(value);
}

asyncPrint('hello world', 50);

async 函数有多种使用形式。

// 函数声明
async function foo() {}

// 函数表达式
const foo = async function () {};

// 对象的方法
let obj = { async foo() {} };
obj.foo().then(...)

// Class 的方法
class Storage {
  constructor() {
    this.cachePromise = caches.open('avatars');
  }

  async getAvatar(name) {
    const cache = await this.cachePromise;
    return cache.match(`/avatars/${name}.jpg`);
  }
}

const storage = new Storage();
storage.getAvatar('jake').then(…);

// 箭头函数
const foo = async () => {};

语法

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];
}
getTitle('https://tc39.github.io/ecma262/').then(console.log)
// "ECMAScript 2017 Language Specification"
</code></pre> 
 <p>上面代码中,函数<code>getTitle</code>内部有三个操作:抓取网页、取出文本、匹配页面标题。只有这三个操作全部完成,才会执行<code>then</code>方法里面的<code>console.log</code>。</p> 
 <h4>await</h4> 
 <p>正常情况下,<code>await</code>命令后面是一个 Promise 对象,返回该对象的结果。如果不是 Promise 对象,就直接返回对应的值。</p> 
 <pre><code class="javascript">async function f() {
  // 等同于
  // return 123;
  return await 123;
}

f().then(v => console.log(v))
// 123
</code></pre> 
 <p>上面代码中,<code>await</code>命令的参数是数值<code>123</code>,这时等同于<code>return 123</code>。<br> 另一种情况是,<code>await</code>命令后面是一个<code>thenable</code>对象(即定义<code>then</code>方法的对象),那么<code>await</code>会将其等同于 Promise 对象。</p> 
 <pre><code class="javascript">class Sleep {
  constructor(timeout) {
    this.timeout = timeout;
  }
  then(resolve, reject) {
    const startTime = Date.now();
    setTimeout(
      () => resolve(Date.now() - startTime),
      this.timeout
    );
  }
}

(async () => {
  const sleepTime = await new Sleep(1000);
  console.log(sleepTime);
})();
// 1000
</code></pre> 
 <p>上面代码中,<code>await</code>命令后面是一个<code>Sleep</code>对象的实例。这个实例不是 Promise 对象,但是因为定义了<code>then</code>方法,<code>await</code>会将其视为<code>Promise</code>处理。</p> 
 <p>这个例子还演示了如何实现休眠效果。JavaScript 一直没有休眠的语法,但是借助<code>await</code>命令就可以让程序停顿指定的时间。下面给出了一个简化的<code>sleep</code>实现。</p> 
 <pre><code class="javascript">function sleep(interval) {
  return new Promise(resolve => {
    setTimeout(resolve, interval);
  })
}

// 用法
async function one2FiveInAsync() {
  for(let i = 1; i <= 5; i++) {
    console.log(i);
    await sleep(1000);
  }
}

one2FiveInAsync();
</code></pre> 
 <p><code>await</code>命令后面的 Promise 对象如果变为<code>reject</code>状态,则<code>reject</code>的参数会被<code>catch</code>方法的回调函数接收到。</p> 
 <pre><code class="javascript">async function f() {
  await Promise.reject('出错了');
}

f()
.then(v => console.log(v))
.catch(e => console.log(e))
// 出错了
</code></pre> 
 <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> 
 <pre><code class="javascript">async function f() {
  await Promise.reject('出错了');
  await Promise.resolve('hello world'); // 不会执行
}
</code></pre> 
 <p>上面代码中,第二个<code>await</code>语句是不会执行的,因为第一个<code>await</code>语句状态变成了<code>reject</code>。</p> 
 <p>有时,我们希望即使前一个异步操作失败,也不要中断后面的异步操作。这时可以将第一个<code>await</code>放在<code>try...catch</code>结构里面,这样不管这个异步操作是否成功,第二个<code>await</code>都会执行。</p> 
 <pre><code class="javascript">async function f() {
  try {
    await Promise.reject('出错了');
  } catch(e) {
  }
  return await Promise.resolve('hello world');
}

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

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

f()
.then(v => console.log(v))
.catch(e => console.log(e))
// Error:出错了
</code></pre> 
 <p>上面代码中,<code>async</code>函数<code>f</code>执行后,<code>await</code>后面的 Promise 对象会抛出一个错误对象,导致<code>catch</code>方法的回调函数被调用,它的参数就是抛出的错误对象。具体的执行机制,可以参考后文的“async 函数的实现原理”。</p> 
 <p>防止出错的方法,也是将其放在<code>try...catch</code>代码块之中。</p> 
 <pre><code class="javascript">async function f() {
  try {
    await new Promise(function (resolve, reject) {
      throw new Error('出错了');
    });
  } catch(e) {
  }
  return await('hello world');
}
</code></pre> 
 <p>如果有多个<code>await</code>命令,可以统一放在<code>try...catch</code>结构中。</p> 
 <pre><code class="javascript">async function main() {
  try {
    const val1 = await firstStep();
    const val2 = await secondStep(val1);
    const val3 = await thirdStep(val1, val2);

    console.log('Final: ', val3);
  }
  catch (err) {
    console.error(err);
  }
}
</code></pre> 
 <p>下面的例子使用<code>try...catch</code>结构,实现多次重复尝试。</p> 
 <pre><code class="javascript">const superagent = require('superagent');
const NUM_RETRIES = 3;

async function test() {
  let i;
  for (i = 0; i < NUM_RETRIES; ++i) {
    try {
      await superagent.get('http://google.com/this-throws-an-error');
      break;
    } catch(err) {}
  }
  console.log(i); // 3
}

test();
</code></pre> 
 <p>上面代码中,如果<code>await</code>操作成功,就会使用<code>break</code>语句退出循环;如果失败,会被<code>catch</code>语句捕捉,然后进入下一轮循环。</p> 
 <h3>使用注意点</h3> 
 <p>第一点,前面已经说过,<code>await</code>命令后面的<code>Promise</code>对象,运行结果可能是<code>rejected</code>,所以最好把<code>await</code>命令放在<code>try...catch</code>代码块中。</p> 
 <pre><code class="javascript">async function myFunction() {
  try {
    await somethingThatReturnsAPromise();
  } catch (err) {
    console.log(err);
  }
}

// 另一种写法

async function myFunction() {
  await somethingThatReturnsAPromise()
  .catch(function (err) {
    console.log(err);
  });
}
</code></pre> 
 <p>第二点,多个<code>await</code>命令后面的异步操作,如果不存在继发关系,最好让它们同时触发。</p> 
 <pre><code class="javascript">let foo = await getFoo();
let bar = await getBar();
</code></pre> 
 <p>上面代码中,<code>getFoo</code>和<code>getBar</code>是两个独立的异步操作(即互不依赖),被写成继发关系。这样比较耗时,因为只有<code>getFoo</code>完成以后,才会执行<code>getBar</code>,完全可以让它们同时触发。</p> 
 <pre><code class="javascript">// 写法一
let [foo, bar] = await Promise.all([getFoo(), getBar()]);

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

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

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

  for (let doc of docs) {
    await db.post(doc);
  }
}
</code></pre> 
 <p>如果确实希望多个请求并发执行,可以使用<code>Promise.all</code>方法。当三个请求都会<code>resolved</code>时,下面两种写法效果相同。</p> 
 <pre><code class="javascript">async function dbFuc(db) {
  let docs = [{}, {}, {}];
  let promises = docs.map((doc) => db.post(doc));

  let results = await Promise.all(promises);
  console.log(results);
}

// 或者使用下面的写法

async function dbFuc(db) {
  let docs = [{}, {}, {}];
  let promises = docs.map((doc) => db.post(doc));

  let results = [];
  for (let promise of promises) {
    results.push(await promise);
  }
  console.log(results);
}
</code></pre> 
 <p>第四点,async 函数可以保留运行堆栈。</p> 
 <pre><code class="javascript">const a = () => {
  b().then(() => c());
};
</code></pre> 
 <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> 
 <pre><code class="javascript">const a = async () => {
  await b();
  c();
};
</code></pre> 
 <p>上面代码中,<code>b()</code>运行的时候,<code>a()</code>是暂停执行,上下文环境都保存着。一旦<code>b()</code>或<code>c()</code>报错,错误堆栈将包括<code>a()</code>。</p> 
 <h2>async 函数的实现原理</h2> 
 <p>async 函数的实现原理,就是将 Generator 函数和自动执行器,包装在一个函数里。</p> 
 <pre><code class="javascript">async function fn(args) {
  // ...
}

// 等同于

function fn(args) {
  return spawn(function* () {
    // ...
  });
}
</code></pre> 
 <p>所有的<code>async</code>函数都可以写成上面的第二种形式,其中的<code>spawn</code>函数就是自动执行器。</p> 
 <p>下面给出<code>spawn</code>函数的实现,基本就是前文自动执行器的翻版。</p> 
 <pre><code class="javascript">function spawn(genF) {
  return new Promise(function(resolve, reject) {
    const gen = genF();
    function step(nextF) {
      let next;
      try {
        next = nextF();
      } catch(e) {
        return reject(e);
      }
      if(next.done) {
        return resolve(next.value);
      }
      Promise.resolve(next.value).then(function(v) {
        step(function() { return gen.next(v); });
      }, function(e) {
        step(function() { return gen.throw(e); });
      });
    }
    step(function() { return gen.next(undefined); });
  });
}
</code></pre> 
 <h2>与其他异步处理方法的比较</h2> 
 <p>我们通过一个例子,来看 async 函数与 Promise、Generator 函数的比较。</p> 
 <p>假定某个 DOM 元素上面,部署了一系列的动画,前一个动画结束,才能开始后一个。如果当中有一个动画出错,就不再往下执行,返回上一个成功执行的动画的返回值。</p> 
 <p>首先是 Promise 的写法。</p> 
 <pre><code class="javascript">function chainAnimationsPromise(elem, animations) {

  // 变量ret用来保存上一个动画的返回值
  let ret = null;

  // 新建一个空的Promise
  let p = Promise.resolve();

  // 使用then方法,添加所有动画
  for(let anim of animations) {
    p = p.then(function(val) {
      ret = val;
      return anim(elem);
    });
  }

  // 返回一个部署了错误捕捉机制的Promise
  return p.catch(function(e) {
    /* 忽略错误,继续执行 */
  }).then(function() {
    return ret;
  });

}
</code></pre> 
 <p>虽然 Promise 的写法比回调函数的写法大大改进,但是一眼看上去,代码完全都是 Promise 的 API(<code>then</code>、<code>catch</code>等等),操作本身的语义反而不容易看出来。</p> 
 <p>接着是 Generator 函数的写法。</p> 
 <pre><code class="javascript">function chainAnimationsGenerator(elem, animations) {

  return spawn(function*() {
    let ret = null;
    try {
      for(let anim of animations) {
        ret = yield anim(elem);
      }
    } catch(e) {
      /* 忽略错误,继续执行 */
    }
    return ret;
  });

}
</code></pre> 
 <p>上面代码使用 Generator 函数遍历了每个动画,语义比 Promise 写法更清晰,用户定义的操作全部都出现在<code>spawn</code>函数的内部。这个写法的问题在于,必须有一个任务运行器,自动执行 Generator 函数,上面代码的<code>spawn</code>函数就是自动执行器,它返回一个 Promise 对象,而且必须保证<code>yield</code>语句后面的表达式,必须返回一个 Promise。</p> 
 <p>最后是 async 函数的写法。</p> 
 <pre><code class="javascript">async function chainAnimationsAsync(elem, animations) {
  let ret = null;
  try {
    for(let anim of animations) {
      ret = await anim(elem);
    }
  } catch(e) {
    /* 忽略错误,继续执行 */
  }
  return ret;
}
</code></pre> 
 <p>可以看到 Async 函数的实现最简洁,最符合语义,几乎没有语义不相关的代码。它将 Generator 写法中的自动执行器,改在语言层面提供,不暴露给用户,因此代码量最少。如果使用 Generator 写法,自动执行器需要用户自己提供。</p> 
 <h2>实例:按顺序完成异步操作</h2> 
 <p>实际开发中,经常遇到一组异步操作,需要按照顺序完成。比如,依次远程读取一组 URL,然后按照读取的顺序输出结果。</p> 
 <p>Promise 的写法如下。</p> 
 <pre><code class="javascript">function logInOrder(urls) {
  // 远程读取所有URL
  const textPromises = urls.map(url => {
    return fetch(url).then(response => response.text());
  });

  // 按次序输出
  textPromises.reduce((chain, textPromise) => {
    return chain.then(() => textPromise)
      .then(text => console.log(text));
  }, Promise.resolve());
}
</code></pre> 
 <p>上面代码使用<code>fetch</code>方法,同时远程读取一组 URL。每个<code>fetch</code>操作都返回一个 Promise 对象,放入<code>textPromises</code>数组。然后,<code>reduce</code>方法依次处理每个 Promise 对象,然后使用<code>then</code>,将所有 Promise 对象连起来,因此就可以依次输出结果。</p> 
 <p>这种写法不太直观,可读性比较差。下面是 async 函数实现。</p> 
 <pre><code class="javascript">async function logInOrder(urls) {
  for (const url of urls) {
    const response = await fetch(url);
    console.log(await response.text());
  }
}
</code></pre> 
 <p>上面代码确实大大简化,问题是所有远程操作都是继发。只有前一个 URL 返回结果,才会去读取下一个 URL,这样做效率很差,非常浪费时间。我们需要的是并发发出远程请求。</p> 
 <pre><code class="javascript">async function logInOrder(urls) {
  // 并发读取远程URL
  const textPromises = urls.map(async url => {
    const response = await fetch(url);
    return response.text();
  });

  // 按次序输出
  for (const textPromise of textPromises) {
    console.log(await textPromise);
  }
}
</code></pre> 
 <p>上面代码中,虽然<code>map</code>方法的参数是<code>async</code>函数,但它是并发执行的,因为只有<code>async</code>函数内部是继发执行,外部不受影响。后面的<code>for..of</code>循环内部使用了<code>await</code>,因此实现了按顺序输出。</p> 
 <h2>顶层 await</h2> 
 <p>根据语法规格,<code>await</code>命令只能出现在 async 函数内部,否则都会报错。</p> 
 <pre><code class="javascript">// 报错
const data = await fetch('https://api.example.com');
</code></pre> 
 <p>上面代码中,<code>await</code>命令独立使用,没有放在 async 函数里面,就会报错。</p> 
 <p>目前,有一个语法提案,允许在模块的顶层独立使用<code>await</code>命令。这个提案的目的,是借用<code>await</code>解决模块异步加载的问题。</p> 
 <pre><code class="javascript">// awaiting.js
let output;
async function main() {
  const dynamic = await import(someMission);
  const data = await fetch(url);
  output = someProcess(dynamic.default, data);
}
main();
export { output };
</code></pre> 
 <p>上面代码中,模块<code>awaiting.js</code>的输出值<code>output</code>,取决于异步操作。我们把异步操作包装在一个 async 函数里面,然后调用这个函数,只有等里面的异步操作都执行,变量<code>output</code>才会有值,否则就返回<code>undefined</code>。</p> 
 <p>上面的代码也可以写成立即执行函数的形式。</p> 
 <pre><code class="javascript">// awaiting.js
let output;
(async function main() {
  const dynamic = await import(someMission);
  const data = await fetch(url);
  output = someProcess(dynamic.default, data);
})();
export { output };
</code></pre> 
 <p>下面是加载这个模块的写法。</p> 
 <pre><code class="javascript">// usage.js
import { output } from "./awaiting.js";

function outputPlusValue(value) { return output + value }

console.log(outputPlusValue(100));
setTimeout(() => console.log(outputPlusValue(100), 1000);
</code></pre> 
 <p>上面代码中,<code>outputPlusValue()</code>的执行结果,完全取决于执行的时间。如果<code>awaiting.js</code>里面的异步操作没执行完,加载进来的<code>output</code>的值就是<code>undefined</code>。</p> 
 <p>目前的解决方法,就是让原始模块输出一个 Promise 对象,从这个 Promise 对象判断异步操作有没有结束。</p> 
 <pre><code class="javascript">// awaiting.js
let output;
export default (async function main() {
  const dynamic = await import(someMission);
  const data = await fetch(url);
  output = someProcess(dynamic.default, data);
})();
export { output };
</code></pre> 
 <p>上面代码中,<code>awaiting.js</code>除了输出<code>output</code>,还默认输出一个 Promise 对象(async 函数立即执行后,返回一个 Promise 对象),从这个对象判断异步操作是否结束。</p> 
 <p>下面是加载这个模块的新的写法。</p> 
 <pre><code class="javascript">// usage.js
import promise, { output } from "./awaiting.js";

function outputPlusValue(value) { return output + value }

promise.then(() => {
  console.log(outputPlusValue(100));
  setTimeout(() => console.log(outputPlusValue(100), 1000);
});
</code></pre> 
 <p>上面代码中,将<code>awaiting.js</code>对象的输出,放在<code>promise.then()</code>里面,这样就能保证异步操作完成以后,才去读取<code>output</code>。</p> 
 <p>这种写法比较麻烦,等于要求模块的使用者遵守一个额外的使用协议,按照特殊的方法使用这个模块。一旦你忘了要用 Promise 加载,只使用正常的加载方法,依赖这个模块的代码就可能出错。而且,如果上面的<code>usage.js</code>又有对外的输出,等于这个依赖链的所有模块都要使用 Promise 加载。</p> 
 <p>顶层的<code>await</code>命令,就是为了解决这个问题。它保证只有异步操作完成,模块才会输出值。</p> 
 <pre><code class="javascript">// awaiting.js
const dynamic = import(someMission);
const data = fetch(url);
export const output = someProcess((await dynamic).default, await data);
</code></pre> 
 <p>上面代码中,两个异步操作在输出的时候,都加上了<code>await</code>命令。只有等到异步操作完成,这个模块才会输出值。</p> 
 <p>加载这个模块的写法如下。</p> 
 <pre><code class="javascript">// usage.js
import { output } from "./awaiting.js";
function outputPlusValue(value) { return output + value }

console.log(outputPlusValue(100));
setTimeout(() => console.log(outputPlusValue(100), 1000);
</code></pre> 
 <p>上面代码的写法,与普通的模块加载完全一样。也就是说,模块的使用者完全不用关心,依赖模块的内部有没有异步操作,正常加载即可。</p> 
 <p>这时,模块的加载会等待依赖模块(上例是<code>awaiting.js</code>)的异步操作完成,才执行后面的代码,有点像暂停在那里。所以,它总是会得到正确的<code>output</code>,不会因为加载时机的不同,而得到不一样的值。</p> 
 <p>下面是顶层<code>await</code>的一些使用场景。</p> 
 <pre><code class="javascript">// import() 方法加载
const strings = await import(`/i18n/${navigator.language}`);

// 数据库操作
const connection = await dbConnector();

// 依赖回滚
let jQuery;
try {
  jQuery = await import('https://cdn-a.com/jQuery');
} catch {
  jQuery = await import('https://cdn-b.com/jQuery');
}
</code></pre> 
 <p>注意,如果加载多个包含顶层<code>await</code>命令的模块,加载命令是同步执行的。</p> 
 <pre><code class="javascript">// x.js
console.log("X1");
await new Promise(r => setTimeout(r, 1000));
console.log("X2");

// y.js
console.log("Y");

// z.js
import "./x.js";
import "./y.js";
console.log("Z");
</code></pre> 
 <p>上面代码有三个模块,最后的<code>z.js</code>加载<code>x.js</code>和<code>y.js</code>,打印结果是<code>X1</code>、<code>Y</code>、<code>X2</code>、<code>Z</code>。这说明,<code>z.js</code>并没有等待<code>x.js</code>加载完成,再去加载<code>y.js</code>。<br> 顶层的<code>await</code>命令有点像,交出代码的执行权给其他的模块加载,等异步操作完成后,再拿回执行权,继续向下执行。</p> 
</article>
                            </div>
                        </div>
                    </div>
                    <!--PC和WAP自适应版-->
                    <div id="SOHUCS" sid="1289288135041163264"></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——异步操作)</h4>
        <div id="paradigm-article-related">
            <div class="recommend-post mb30">
                <ul class="widget-links">
                    <li><a href="/article/1835154546289111040.htm"
                           title="EcmaScript和JavaScript的区别" target="_blank">EcmaScript和JavaScript的区别</a>
                        <span class="text-muted">每天吃八顿</span>
<a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a><a class="tag" taget="_blank" href="/search/ecmascript/1.htm">ecmascript</a>
                        <div>ECMAScript和JavaScript是经常被混淆的两个术语,但实际上它们之间存在一些区别:ECMAScript:ECMAScript(通常缩写为ES,并且有版本号如ES5,ES6和ES7等)是由ECMA国际(EuropeanComputerManufacturersAssociation)制定的一种脚本语言的规范。这个规范定义了语法、命令、数据类型等基本元素。ECMAScript是一种规范,</div>
                    </li>
                    <li><a href="/article/1834993261471690752.htm"
                           title="1.forEach" target="_blank">1.forEach</a>
                        <span class="text-muted">Night_LION</span>

                        <div>varcolors=["red","blue","green"];//ES5遍历数组方法for(vari=0;i//console.log(colors[i]);}//ES6forEachcolors.forEach(function(color){//console.log(color);});//练习:遍历数组中的值,并计算总和varnumbers=[1,2,3,4,5];varsum=0;f</div>
                    </li>
                    <li><a href="/article/1834981318258159616.htm"
                           title="windows C++-并行编程-PPL任务并行(二)" target="_blank">windows C++-并行编程-PPL任务并行(二)</a>
                        <span class="text-muted">sului</span>
<a class="tag" taget="_blank" href="/search/windows/1.htm">windows</a><a class="tag" taget="_blank" href="/search/C%2B%2B%E5%B9%B6%E8%A1%8C%E7%BC%96%E7%A8%8B%E6%8A%80%E6%9C%AF/1.htm">C++并行编程技术</a><a class="tag" taget="_blank" href="/search/windows/1.htm">windows</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>延续任务在异步编程中,一个异步操作在完成时调用另一个操作并将数据传递到其中的情况非常常见。传统上,这使用回调方法来完成。在并发运行时中,延续任务提供了同样的功能。延续任务(也简称为“延续”)是一个异步任务,由另一个任务(称为先行)在完成时调用。使用延续可以:将数据从前面的任务传递到延续;指定调用或不调用延续所依据的精确条件;在延续启动之前取消延续,或在延续正在运行时以协作方式取消延续;提供有关应如</div>
                    </li>
                    <li><a href="/article/1834952559333306368.htm"
                           title="windows C++-并行编程-PPL任务并行(一)" target="_blank">windows C++-并行编程-PPL任务并行(一)</a>
                        <span class="text-muted">sului</span>
<a class="tag" taget="_blank" href="/search/windows/1.htm">windows</a><a class="tag" taget="_blank" href="/search/C%2B%2B%E5%B9%B6%E8%A1%8C%E7%BC%96%E7%A8%8B%E6%8A%80%E6%9C%AF/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/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a>
                        <div>在并发运行时中,任务是执行特定作业并通常与其他任务并行运行的工作单元。任务可以分解为组织成任务组的其他更细化的任务。编写异步代码,并希望在异步操作完成之后进行某种操作时,可使用任务。例如,可以使用一个任务以异步方式从文件读取,然后使用另一个任务(延续任务,本文档稍后会对此进行说明)在数据可用之后处理数据。相反,可以使用任务组将并行工作分解成较小的各部分。例如,假设你有一个将剩余工作划分为两个分区的</div>
                    </li>
                    <li><a href="/article/1834818562884202496.htm"
                           title="前端开发深入了解webpack" target="_blank">前端开发深入了解webpack</a>
                        <span class="text-muted">史努比的大头</span>
<a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a>
                        <div>什么是webpackWebpack是一个现代JavaScript应用程序的模块打包工具。它主要用于将各种资源(如JavaScript、CSS、图片等)打包成一个或多个文件,以优化Web应用的加载性能。Webpack的核心功能包括:模块化:支持将代码拆分为模块,便于管理和重用。打包:将多个模块和资源打包成一个或多个文件,减少HTTP请求。加载器(Loaders):处理不同类型的文件(如转换ES6到E</div>
                    </li>
                    <li><a href="/article/1834817300432252928.htm"
                           title="Reactive 编程-Vert.x" target="_blank">Reactive 编程-Vert.x</a>
                        <span class="text-muted">Flying_Fish_Xuan</span>
<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>Reactive编程与Vert.x:高效异步Java微服务框架一、什么是Reactive编程?Reactive编程是一种异步编程范式,专注于数据流和事件的传播处理。与传统的阻塞式编程不同,Reactive编程能够更好地处理高并发和异步操作,特别适合实时系统、流处理以及需要快速响应的场景。Reactive编程的核心原则包括:响应性(Responsive):系统能够快速响应用户请求,并保持低延迟。弹性</div>
                    </li>
                    <li><a href="/article/1834741917271814144.htm"
                           title="vue IE因Promise无法显示解决办法" target="_blank">vue IE因Promise无法显示解决办法</a>
                        <span class="text-muted">Yao请输入昵称</span>

                        <div>一、ie11打开vue2.0项目空白,控制台报错vuexrequiresaPromisepolyfillinthisbrowserPromise为ES6语法,有的浏览器不支持ES6,所以需要安装babel-polyfill来将ES6转换为浏览器可识别的ES5语法①npminstall--save-devbabel-polyfill②在main.js中引入import"babel-polyfill"</div>
                    </li>
                    <li><a href="/article/1834710748438294528.htm"
                           title="ES6 中的 Symbol 是什么?" target="_blank">ES6 中的 Symbol 是什么?</a>
                        <span class="text-muted">隐逸王</span>

                        <div>前言记得刚找工作那会,几种数据类型是必问题,当时的答案一般都是七种——字符串(String)、数字(Number)、布尔(Boolean)、数组(Array)、对象(Object)、空(Null)、未定义(Undefined),时至今日,某些网络教程上还是这样的分类:不完整的分类其实,随着ECMAScript的发展和完善,在ES6(2015)和ES11(2020)中,又分别增加了Symbol和Bi</div>
                    </li>
                    <li><a href="/article/1834707378814152704.htm"
                           title="ES6+--》正则扩展_es6 正则扩展" target="_blank">ES6+--》正则扩展_es6 正则扩展</a>
                        <span class="text-muted">2401_84170337</span>
<a class="tag" taget="_blank" href="/search/es6/1.htm">es6</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a><a class="tag" taget="_blank" href="/search/ecmascript/1.htm">ecmascript</a>
                        <div>//声明一个字符串letstr='百度'//提取url与标签文本constreg=/(.*)///执行constresult=reg.exec(str)console.log(result);console.log(result[1]);console.log(result[2]);//设置分组名constreg1=/.*)">(?.*)/constresult1=reg1.exec(str)co</div>
                    </li>
                    <li><a href="/article/1834673478599536640.htm"
                           title="vue2与vue3的区别" target="_blank">vue2与vue3的区别</a>
                        <span class="text-muted">longfan_</span>
<a class="tag" taget="_blank" href="/search/vue/1.htm">vue</a>
                        <div>1.vue2和vue3响应式原理发生了改变vue2的响应式原理是利⽤es5的⼀个API,Object.defineProperty()对数据进⾏劫持结合发布订阅模式的⽅式来实现的。vue3中使⽤了es6的proxyAPI对数据代理,通过reactive()函数给每⼀个对象都包⼀层Proxy,通过Proxy监听属性的变化,从⽽实现对数据的监控。这⾥是引相⽐于vue2版本,使⽤proxy的优势如下1.</div>
                    </li>
                    <li><a href="/article/1834614101804937216.htm"
                           title="数组扁平化" target="_blank">数组扁平化</a>
                        <span class="text-muted"></span>
<a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</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/ecmascript/1.htm">ecmascript</a>
                        <div>什么是扁平化定义:扁平化就是将多维数组变成一维数组,不存在数组的嵌套实现扁平化的方法封装flatten1.ES6flatflat(depth)方法会按照一个可指定的深度递归遍历数组,并将所有元素与遍历到的子数组中的元素合并为一个新数组返回。参数:depth(可选)指定要提取嵌套数组的结构深度,默认值为1返回值:返回一个新数组,包含数组与提取嵌套数组的所有元素的新数组使用Infinity,可展开任意</div>
                    </li>
                    <li><a href="/article/1834330617085521920.htm"
                           title="2023.7.15 学习Vue3.x官方文档之异步组件 + <Suspense>(通俗易懂的理解!)" target="_blank">2023.7.15 学习Vue3.x官方文档之异步组件 + <Suspense>(通俗易懂的理解!)</a>
                        <span class="text-muted">夏日友情天_</span>
<a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a><a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</a><a class="tag" taget="_blank" href="/search/vue.js/1.htm">vue.js</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF%E6%A1%86%E6%9E%B6/1.htm">前端框架</a>
                        <div>一、异步组件基本用法相对于正常组件来讲,异步组件,顾名思义,就是组件里有异步操作。(可能说法不准确,但是也是可以这么理解的。定义一个正常的vue组件,我们用defineComponent({}),此处为选项式API。但随着Vue3成为默认版本,出现,使用组合式API编程时,不再显示使用这个API。#Vue提供给我们定义异步组件的方式,下面来看看怎么定义异步组件吧!import{defineAsyn</div>
                    </li>
                    <li><a href="/article/1834286113171271680.htm"
                           title="Unity协程搭配队列开发Tips弹窗模块" target="_blank">Unity协程搭配队列开发Tips弹窗模块</a>
                        <span class="text-muted">傻Q爱</span>
<a class="tag" taget="_blank" href="/search/Unity%E6%8A%80%E6%9C%AF/1.htm">Unity技术</a><a class="tag" taget="_blank" href="/search/unity/1.htm">unity</a><a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/%E6%B8%B8%E6%88%8F%E5%BC%95%E6%93%8E/1.htm">游戏引擎</a>
                        <div>概述在Unity游戏开发过程中,提示系统是提升用户体验的重要组成部分。一个设计良好的提示窗口不仅能及时传达信息给玩家,还应当做到不干扰游戏流程。本文将探讨如何使用Unity的协程(Coroutine)配合队列(Queue)数据结构来构建一个高效且可扩展的Tips弹窗模块。技术模块介绍1.Unity协程(Coroutines)协程是Unity中的一种特殊函数类型,允许异步操作的实现。它能够在执行过程</div>
                    </li>
                    <li><a href="/article/1834065522921140224.htm"
                           title="es6异步函数(二)-深入理解generator" target="_blank">es6异步函数(二)-深入理解generator</a>
                        <span class="text-muted">清汤饺子</span>

                        <div>作为对象属性的Generator函数如果一个对象的属性是Generator函数,可以简写成下面的形式。letobj={*myGeneratorMethod(){···}};直接从实例开始讲解//命名generator函数必须加*,function*gen(){yield'1';yield'2';return'last'}letg1=gen();//手动调用console.log(g1.next()</div>
                    </li>
                    <li><a href="/article/1833948803116396544.htm"
                           title="vue基本语法" target="_blank">vue基本语法</a>
                        <span class="text-muted">多啦爱梦的梦想</span>
<a class="tag" taget="_blank" href="/search/vue/1.htm">vue</a>
                        <div>VUEday01异步函数和回调函数何为异步函数:不会马上执行,需要特定的时机执行的函数,由于是异步的,不会阻塞主线程代码的执行异步函数有哪些:ajax请求,定时器,延时器,文件读取何为回调函数:把一个函数当作参数传递,将来特定的时机调用,这个函数就是回调函数,一般异步操作,都会用到回调函数例如:setTimeout(()=>{console.log(2)},1000)==>定时器里面的打印2不会立</div>
                    </li>
                    <li><a href="/article/1833938347714768896.htm"
                           title="使用vuex从入门到应用(三)" target="_blank">使用vuex从入门到应用(三)</a>
                        <span class="text-muted">剑圣_盖小聂</span>

                        <div>因为mutation必须是同步函数,但是当我们需要异步的时候怎么办呢?这个时候就有了action,先看一下官网对Action的介绍:Action类似于mutation,不同在于:Action提交的是mutation,而不是直接变更状态。Action可以包含任意异步操作。先看效果图:点击加一按钮,数字会延时1秒钟加一,点击减1按钮,延时1秒减一,点击加n按钮,对应的值加随机数效果图首先我们需要在st</div>
                    </li>
                    <li><a href="/article/1833899249880887296.htm"
                           title="VUE3学习路线" target="_blank">VUE3学习路线</a>
                        <span class="text-muted">蜡笔小新星</span>
<a class="tag" taget="_blank" href="/search/Vue/1.htm">Vue</a><a class="tag" taget="_blank" href="/search/%E5%AD%A6%E4%B9%A0/1.htm">学习</a><a class="tag" taget="_blank" href="/search/vue/1.htm">vue</a><a class="tag" taget="_blank" href="/search/%E7%BB%8F%E9%AA%8C%E5%88%86%E4%BA%AB/1.htm">经验分享</a>
                        <div>以下是一份详细的Vue3学习路线,涵盖从基础到进阶的各个方面,以帮助你系统掌握Vue3开发。第一阶段:基础知识理解前端基础HTML:了解文档结构,常用标签,语义化HTML。CSS:学习选择器、布局、Flexbox和Grid,基本的样式应用。JavaScript:理解基本语法、DOM操作、事件处理、异步编程(Promises,async/await),以及ES6+特性(如箭头函数、解构赋值、模块化)</div>
                    </li>
                    <li><a href="/article/1833869873374130176.htm"
                           title="题解 | #字符统计#hashmap + treeset" target="_blank">题解 | #字符统计#hashmap + treeset</a>
                        <span class="text-muted">2301_79125642</span>
<a class="tag" taget="_blank" href="/search/java/1.htm">java</a>
                        <div>双非简历求拷打,秋招够用吗#我的简历长这样##最后再改一次简历#async/await的用途和工作原理async/await是ES8(ES2017)引入的一种用于处理异步操作的语法,它建立在ProVue中组件传值的方式Vue中组件传值的方式主要有以下几种:https://www.nowcoder.com/issue异步编程?异步编程是一种编程模式,用于处理可能会花费较长时间的操作,而不会阻塞其他代</div>
                    </li>
                    <li><a href="/article/1833799648578465792.htm"
                           title="web学习笔记11-node.js基础" target="_blank">web学习笔记11-node.js基础</a>
                        <span class="text-muted">晴天.js</span>
<a class="tag" taget="_blank" href="/search/web-%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/1.htm">web-学习笔记</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a><a class="tag" taget="_blank" href="/search/%E5%AD%A6%E4%B9%A0/1.htm">学习</a><a class="tag" taget="_blank" href="/search/node.js/1.htm">node.js</a>
                        <div>一、ES6ECMAscript->ES是JS的标准规范ES6是JS的第六套标准规范1,块级作用域let声明的变量,会进入暂时性的死区,提升后暂时不允许访问,只有赋值以后才允许访问let声明的变量不允许重复声明块级作用域:大括号之间的语句块,例如if、else。块级作用域下,let和const声明的局部变量或者常量,不允许被块级作用域以外访问let和const即使声明在全局作用域下,也不是全局变量或</div>
                    </li>
                    <li><a href="/article/1833755520025063424.htm"
                           title="export default vs module.exports:JavaScript 模块导出的双雄对决" target="_blank">export default vs module.exports:JavaScript 模块导出的双雄对决</a>
                        <span class="text-muted">正小安</span>
<a class="tag" taget="_blank" href="/search/vue%E6%9D%82%E8%B0%88/1.htm">vue杂谈</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a><a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</a><a class="tag" taget="_blank" href="/search/ecmascript/1.htm">ecmascript</a>
                        <div>exportdefaultvsmodule.exports:JavaScript模块导出的双雄对决在JavaScript的模块化编程中,exportdefault和module.exports是两种不可或缺的语法,它们分别代表了ES6模块系统(也称为ES2015模块或ES6模块)和CommonJS模块系统的核心导出机制。了解它们之间的区别与联系,对于编写可维护、跨平台兼容的JavaScript代码</div>
                    </li>
                    <li><a href="/article/1833707106495197184.htm"
                           title="Vue3异步请求的最佳实践:async/await 与 Promise.then(),Vue3请求接口数据,以及TypeScript中的泛型和任意类型(Vue3请求API,TS中的T 和 any)" target="_blank">Vue3异步请求的最佳实践:async/await 与 Promise.then(),Vue3请求接口数据,以及TypeScript中的泛型和任意类型(Vue3请求API,TS中的T 和 any)</a>
                        <span class="text-muted">北城笑笑</span>
<a class="tag" taget="_blank" href="/search/VueJS/1.htm">VueJS</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a><a class="tag" taget="_blank" href="/search/vue.js/1.htm">vue.js</a>
                        <div>前言在Vue3开发中,异步请求是非常常见的操作,特别是在与后端API交互时。虽然Vue.js自带了一些对异步数据的处理方式,但合理使用异步操作是确保应用顺畅运行的关键。这里我分享一下Vue3异步请求的最佳实践,并探讨async/await和Promise.then()两种处理异步操作的方式,简单记录一下1.请求接口的实现这里,我们使用一个请求接口callAskRecordList,它会从/gpt/</div>
                    </li>
                    <li><a href="/article/1833690336367570944.htm"
                           title="深入理解Kotlin中的异步网络请求处理" target="_blank">深入理解Kotlin中的异步网络请求处理</a>
                        <span class="text-muted">小白学大数据</span>
<a class="tag" taget="_blank" href="/search/kotlin/1.htm">kotlin</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/android/1.htm">android</a><a class="tag" taget="_blank" href="/search/%E7%88%AC%E8%99%AB/1.htm">爬虫</a>
                        <div>在现代移动和Web应用开发中,异步网络请求处理是核心功能之一。Kotlin,作为一种现代、简洁且功能强大的编程语言,提供了多种方式来处理异步任务,使得开发者能够编写出更加高效和响应迅速的应用。本文将深入探讨Kotlin中的异步网络请求处理,包括其原理、优势以及如何在实际项目中实现。异步网络请求的重要性在用户界面(UI)开发中,异步操作是至关重要的。它允许应用在不阻塞主线程的情况下,执行网络请求和其</div>
                    </li>
                    <li><a href="/article/1833488319586070528.htm"
                           title="解构" target="_blank">解构</a>
                        <span class="text-muted">你喜欢吃青椒吗_c744</span>

                        <div>什么是解构?解构与构造数据截然相反。例如,它不是构造一个新的对象或数组,而是逐个拆分现有的对象或数组,来提取你所需要的数据。可以快速取得数组或对象当中的元素或属性,而无需使用arr[x]或者obj[key]等传统方式进行赋值。ES6使用了一种新模式来匹配你想要提取的数值,解构赋值就是采用了这种模式。该模式会映射出你正在解构的数据结构,只有那些与该模式相匹配的数据,才会被提取出来。被解构的数据项位于</div>
                    </li>
                    <li><a href="/article/1833481817437597696.htm"
                           title="Promise、async/await 的使用" target="_blank">Promise、async/await 的使用</a>
                        <span class="text-muted">渡鸦七</span>
<a class="tag" taget="_blank" href="/search/JavaScript/1.htm">JavaScript</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a><a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a>
                        <div>Promise、async/await的使用目录Promiseasync/awaitPromise什么是Promise?Promise是异步编程的一种解决方案,它代表了一个异步操作的最终结果。它是一个对象,用来传递异步操作的消息,而不是直接传递结果。Promise提供统一的API,各种异步操作都可以用同样的方法进行处理,并提供统一的接口。Promise也有三种状态:Pending(等待中):初始状</div>
                    </li>
                    <li><a href="/article/1833479296862220288.htm"
                           title="深入探索从ES6到ES2023" target="_blank">深入探索从ES6到ES2023</a>
                        <span class="text-muted">hai40587</span>
<a class="tag" taget="_blank" href="/search/es6/1.htm">es6</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a><a class="tag" taget="_blank" href="/search/ecmascript/1.htm">ecmascript</a>
                        <div>从ES6到ES2023,我们深入探索ECMAScript(简称ES)的演变与发展,了解这一JavaScript标准背后的技术革新和进步。ECMAScript作为JavaScript的标准化版本,每年都在不断推出新版本,为开发者带来更加丰富和强大的功能。本文将从ES6的引入开始,逐步介绍到最新的ES2023,同时探讨这些新特性对现代Web开发的影响。ECMAScript简介与JavaScript的关</div>
                    </li>
                    <li><a href="/article/1833284518669283328.htm"
                           title="JS中const有没有变量提升" target="_blank">JS中const有没有变量提升</a>
                        <span class="text-muted">北原_春希</span>
<a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/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>在JavaScript中,const关键字用于声明一个只读的常量,其值在初始化后不能被重新赋值。关于变量提升(Hoisting),它是JavaScript中一个重要的概念,指的是无论变量或函数声明在何处,它们都会被“提升”到其所在作用域的最顶部。但是,这个规则不完全适用于const和let声明的变量。变量提升(Hoisting)的传统理解在ES6之前,JavaScript只有var关键字用于声明变</div>
                    </li>
                    <li><a href="/article/1833268382229688320.htm"
                           title="2023前端面试时遇到的面试题" target="_blank">2023前端面试时遇到的面试题</a>
                        <span class="text-muted">No regrets, no return</span>
<a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a><a class="tag" taget="_blank" href="/search/vue.js/1.htm">vue.js</a><a class="tag" taget="_blank" href="/search/%E9%9D%A2%E8%AF%95/1.htm">面试</a>
                        <div>2023前端面试时遇到的面试题1.数组有哪些方法push、pop、unshift、shift、join、forEach、filter、map、find…2.filter和some返回的分别是一个什么filter返回的是一个数组,some返回的是一个布尔值3.es6新增了哪些方法let和cconst、模板字符串()、扩展运算符、for…of、解构、箭头函数、symbol数据类型、Set和Map方法等</div>
                    </li>
                    <li><a href="/article/1833257284948553728.htm"
                           title="ES6至ES2023:深入理解ECMAScript的演变之路" target="_blank">ES6至ES2023:深入理解ECMAScript的演变之路</a>
                        <span class="text-muted">N201871643</span>
<a class="tag" taget="_blank" href="/search/%E7%83%AD%E9%97%A8%E7%9B%B8%E5%85%B3%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB/1.htm">热门相关技术分享</a><a class="tag" taget="_blank" href="/search/ecmascript/1.htm">ecmascript</a><a class="tag" taget="_blank" href="/search/es6/1.htm">es6</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a>
                        <div>ES6至ES2023:深入理解ECMAScript的演变之路目录ES6至ES2023:深入理解ECMAScript的演变之路一、ECMAScript简介二、ES6:里程碑式的版本1.类语法2.模块化3.箭头函数4.承诺5.Set和Map三、ES7至ES12:稳步前进1.ES7(ES2016美)2.ES8(ES2017美)3.ES9(ES2018英)4、ES10(ES2019美)5.ES11(ES2</div>
                    </li>
                    <li><a href="/article/1833197056915763200.htm"
                           title="JavaScript Promise" target="_blank">JavaScript Promise</a>
                        <span class="text-muted">我是一个粉刷酱</span>

                        <div>浏览器支持推荐使用Chrome以及Firefox浏览器开局放图,忍不住吐槽一下----垃圾IE!!。什么是PromiseThePromiseobjectrepresentstheeventualcompletion(orfailure)ofanasynchronousoperation,anditsresultingvalue.Promise对象表示异步操作的最终完成(或失败)及其结果值。也就是说</div>
                    </li>
                    <li><a href="/article/1832927069919604736.htm"
                           title="浅谈Unity协程的工作机制" target="_blank">浅谈Unity协程的工作机制</a>
                        <span class="text-muted">王维志</span>
<a class="tag" taget="_blank" href="/search/unity/1.htm">unity</a><a class="tag" taget="_blank" href="/search/windows/1.htm">windows</a><a class="tag" taget="_blank" href="/search/%E6%B8%B8%E6%88%8F%E5%BC%95%E6%93%8E/1.htm">游戏引擎</a>
                        <div>一.什么是协程协程概述在Unity中,协程(Coroutine)是一种非常常用的机制,用于非阻塞地处理需要跨越多个帧、等待某些条件或延迟一段时间才能完成的任务。Unity的协程通过C#的IEnumerator和yieldreturn实现,使得你可以在游戏主线程中以一种简洁的方式执行异步操作,而不需要使用复杂的多线程或回调。协程允许你暂停代码的执行,并在稍后的某个时间点恢复执行。适合处理游一些常见需</div>
                    </li>
                                <li><a href="/article/85.htm"
                                       title="ztree异步加载" target="_blank">ztree异步加载</a>
                                    <span class="text-muted">3213213333332132</span>
<a class="tag" taget="_blank" href="/search/JavaScript/1.htm">JavaScript</a><a class="tag" taget="_blank" href="/search/Ajax/1.htm">Ajax</a><a class="tag" taget="_blank" href="/search/json/1.htm">json</a><a class="tag" taget="_blank" href="/search/Web/1.htm">Web</a><a class="tag" taget="_blank" href="/search/ztree/1.htm">ztree</a>
                                    <div>相信新手用ztree的时候,对异步加载会有些困惑,我开始的时候也是看了API花了些时间才搞定了异步加载,在这里分享给大家。 
我后台代码生成的是json格式的数据,数据大家按各自的需求生成,这里只给出前端的代码。 
 
设置setting,这里只关注async属性的配置 
 

            var setting = {
            	//异步加载配置	
      </div>
                                </li>
                                <li><a href="/article/212.htm"
                                       title="thirft rpc 具体调用流程" target="_blank">thirft rpc 具体调用流程</a>
                                    <span class="text-muted">BlueSkator</span>
<a class="tag" taget="_blank" href="/search/%E4%B8%AD%E9%97%B4%E4%BB%B6/1.htm">中间件</a><a class="tag" taget="_blank" href="/search/rpc/1.htm">rpc</a><a class="tag" taget="_blank" href="/search/thrift/1.htm">thrift</a>
                                    <div>Thrift调用过程中,Thrift客户端和服务器之间主要用到传输层类、协议层类和处理类三个主要的核心类,这三个类的相互协作共同完成rpc的整个调用过程。在调用过程中将按照以下顺序进行协同工作: 
        (1)     将客户端程序调用的函数名和参数传递给协议层(TProtocol),协议</div>
                                </li>
                                <li><a href="/article/339.htm"
                                       title="异或运算推导, 交换数据" target="_blank">异或运算推导, 交换数据</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/%E5%BC%82%E6%88%96/1.htm">异或</a><a class="tag" taget="_blank" href="/search/%5E/1.htm">^</a>
                                    <div>/*
 * 5 0101
 * 9 1010
 *
 * 5 ^ 5
 * 0101
 * 0101
 * -----
 * 0000
 * 得出第一个规律: 相同的数进行异或, 结果是0
 *
 * 9 ^ 5 ^ 6
 * 1010
 * 0101
 * ----
 * 1111
 *
 * 1111
 * 0110
 * ----
 * 1001
 </div>
                                </li>
                                <li><a href="/article/466.htm"
                                       title="事件源对象" target="_blank">事件源对象</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/593.htm"
                                       title="MySql配置及相关命令" target="_blank">MySql配置及相关命令</a>
                                    <span class="text-muted">g21121</span>
<a class="tag" taget="_blank" href="/search/mysql/1.htm">mysql</a>
                                    <div>        MySQL安装完毕后我们需要对它进行一些设置及性能优化,主要包括字符集设置,启动设置,连接优化,表优化,分区优化等等。 
  
        一 修改MySQL密码及用户 
     </div>
                                </li>
                                <li><a href="/article/720.htm"
                                       title="[简单]poi删除excel 2007超链接" target="_blank">[简单]poi删除excel 2007超链接</a>
                                    <span class="text-muted">53873039oycg</span>
<a class="tag" taget="_blank" href="/search/Excel/1.htm">Excel</a>
                                    <div>      采用解析sheet.xml方式删除超链接,缺点是要打开文件2次,代码如下: 
     
public void removeExcel2007AllHyperLink(String filePath) throws Exception {
		OPCPackage ocPkg = OPCPac</div>
                                </li>
                                <li><a href="/article/847.htm"
                                       title="Struts2添加 open flash chart" target="_blank">Struts2添加 open flash chart</a>
                                    <span class="text-muted">云端月影</span>

                                    <div>准备以下开源项目: 
1. Struts 2.1.6 
2. Open Flash Chart 2 Version 2 Lug Wyrm Charmer (28th, July 2009) 
3. jofc2,这东西不知道是没做好还是什么意思,好像和ofc2不怎么匹配,最好下源码,有什么问题直接改。 
4. log4j 
 
用eclipse新建动态网站,取名OFC2Demo,将Struts2 l</div>
                                </li>
                                <li><a href="/article/974.htm"
                                       title="spring包详解" target="_blank">spring包详解</a>
                                    <span class="text-muted">aijuans</span>
<a class="tag" taget="_blank" href="/search/spring/1.htm">spring</a>
                                    <div>  
下载的spring包中文件及各种包众多,在项目中往往只有部分是我们必须的,如果不清楚什么时候需要什么包的话,看看下面就知道了。 aspectj目录下是在Spring框架下使用aspectj的源代码和测试程序文件。Aspectj是java最早的提供AOP的应用框架。 dist 目录下是Spring 的发布包,关于发布包下面会详细进行说明。 docs&nb</div>
                                </li>
                                <li><a href="/article/1101.htm"
                                       title="网站推广之seo概念" target="_blank">网站推广之seo概念</a>
                                    <span class="text-muted">antonyup_2006</span>
<a class="tag" taget="_blank" href="/search/%E7%AE%97%E6%B3%95/1.htm">算法</a><a class="tag" taget="_blank" href="/search/Web/1.htm">Web</a><a class="tag" taget="_blank" href="/search/%E5%BA%94%E7%94%A8%E6%9C%8D%E5%8A%A1%E5%99%A8/1.htm">应用服务器</a><a class="tag" taget="_blank" href="/search/%E6%90%9C%E7%B4%A2%E5%BC%95%E6%93%8E/1.htm">搜索引擎</a><a class="tag" taget="_blank" href="/search/Google/1.htm">Google</a>
                                    <div>   持续开发一年多的b2c网站终于在08年10月23日上线了。作为开发人员的我在修改bug的同时,准备了解下网站的推广分析策略。 
    所谓网站推广,目的在于让尽可能多的潜在用户了解并访问网站,通过网站获得有关产品和服务等信息,为最终形成购买决策提供支持。 
    网站推广策略有很多,seo,email,adv</div>
                                </li>
                                <li><a href="/article/1228.htm"
                                       title="单例模式,sql注入,序列" target="_blank">单例模式,sql注入,序列</a>
                                    <span class="text-muted">百合不是茶</span>
<a class="tag" taget="_blank" href="/search/%E5%8D%95%E4%BE%8B%E6%A8%A1%E5%BC%8F/1.htm">单例模式</a><a class="tag" taget="_blank" href="/search/%E5%BA%8F%E5%88%97/1.htm">序列</a><a class="tag" taget="_blank" href="/search/sql%E6%B3%A8%E5%85%A5/1.htm">sql注入</a><a class="tag" taget="_blank" href="/search/%E9%A2%84%E7%BC%96%E8%AF%91/1.htm">预编译</a>
                                    <div>  
序列在前面写过有关的博客,也有过总结,但是今天在做一个JDBC操作数据库的相关内容时 需要使用序列创建一个自增长的字段  居然不会了,所以将序列写在本篇的前面 
  
 1,序列是一个保存数据连续的增长的一种方式; 
序列的创建; 
 CREATE SEQUENCE seq_pro
  2  INCREMENT BY 1 -- 每次加几个
  3 </div>
                                </li>
                                <li><a href="/article/1355.htm"
                                       title="Mockito单元测试实例" target="_blank">Mockito单元测试实例</a>
                                    <span class="text-muted">bijian1013</span>
<a class="tag" taget="_blank" href="/search/%E5%8D%95%E5%85%83%E6%B5%8B%E8%AF%95/1.htm">单元测试</a><a class="tag" taget="_blank" href="/search/mockito/1.htm">mockito</a>
                                    <div>Mockito单元测试实例: 
public class SettingServiceTest {
    
    private List<PersonDTO> personList = new ArrayList<PersonDTO>();
    
    @InjectMocks
    private SettingPojoService settin</div>
                                </li>
                                <li><a href="/article/1482.htm"
                                       title="精通Oracle10编程SQL(9)使用游标" target="_blank">精通Oracle10编程SQL(9)使用游标</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>/*
 *使用游标
 */
--显示游标
--在显式游标中使用FETCH...INTO语句
DECLARE
   CURSOR emp_cursor is 
      select ename,sal from emp where deptno=1;
   v_ename emp.ename%TYPE;
   v_sal emp.sal%TYPE;
begin
   ope</div>
                                </li>
                                <li><a href="/article/1609.htm"
                                       title="【Java语言】动态代理" target="_blank">【Java语言】动态代理</a>
                                    <span class="text-muted">bit1129</span>
<a class="tag" taget="_blank" href="/search/java%E8%AF%AD%E8%A8%80/1.htm">java语言</a>
                                    <div>  JDK接口动态代理 
JDK自带的动态代理通过动态的根据接口生成字节码(实现接口的一个具体类)的方式,为接口的实现类提供代理。被代理的对象和代理对象通过InvocationHandler建立关联 
  
package com.tom;

import com.tom.model.User;
import com.tom.service.IUserService;
</div>
                                </li>
                                <li><a href="/article/1736.htm"
                                       title="Java通信之URL通信基础" target="_blank">Java通信之URL通信基础</a>
                                    <span class="text-muted">白糖_</span>
<a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/jdk/1.htm">jdk</a><a class="tag" taget="_blank" href="/search/webservice/1.htm">webservice</a><a class="tag" taget="_blank" href="/search/%E7%BD%91%E7%BB%9C%E5%8D%8F%E8%AE%AE/1.htm">网络协议</a><a class="tag" taget="_blank" href="/search/ITeye/1.htm">ITeye</a>
                                    <div>java对网络通信以及提供了比较全面的jdk支持,java.net包能让程序员直接在程序中实现网络通信。 
在技术日新月异的现在,我们能通过很多方式实现数据通信,比如webservice、url通信、socket通信等等,今天简单介绍下URL通信。 
学习准备:建议首先学习java的IO基础知识 
  
URL是统一资源定位器的简写,URL可以访问Internet和www,可以通过url</div>
                                </li>
                                <li><a href="/article/1863.htm"
                                       title="博弈Java讲义 - Java线程同步 (1)" target="_blank">博弈Java讲义 - Java线程同步 (1)</a>
                                    <span class="text-muted">boyitech</span>
<a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/%E5%A4%9A%E7%BA%BF%E7%A8%8B/1.htm">多线程</a><a class="tag" taget="_blank" href="/search/%E5%90%8C%E6%AD%A5/1.htm">同步</a><a class="tag" taget="_blank" href="/search/%E9%94%81/1.htm">锁</a>
                                    <div>  
在并发编程中经常会碰到多个执行线程共享资源的问题。例如多个线程同时读写文件,共用数据库连接,全局的计数器等。如果不处理好多线程之间的同步问题很容易引起状态不一致或者其他的错误。 
   同步不仅可以阻止一个线程看到对象处于不一致的状态,它还可以保证进入同步方法或者块的每个线程,都看到由同一锁保护的之前所有的修改结果。处理同步的关键就是要正确的识别临界条件(cri</div>
                                </li>
                                <li><a href="/article/1990.htm"
                                       title="java-给定字符串,删除开始和结尾处的空格,并将中间的多个连续的空格合并成一个。" target="_blank">java-给定字符串,删除开始和结尾处的空格,并将中间的多个连续的空格合并成一个。</a>
                                    <span class="text-muted">bylijinnan</span>
<a class="tag" taget="_blank" href="/search/java/1.htm">java</a>
                                    <div>

public class DeleteExtraSpace {

	/**
	 * 题目:给定字符串,删除开始和结尾处的空格,并将中间的多个连续的空格合并成一个。
	 * 方法1.用已有的String类的trim和replaceAll方法
	 * 方法2.全部用正则表达式,这个我不熟
	 * 方法3.“重新发明轮子”,从头遍历一次
	 */
	public static v</div>
                                </li>
                                <li><a href="/article/2117.htm"
                                       title="An error has occurred.See the log file错误解决!" target="_blank">An error has occurred.See the log file错误解决!</a>
                                    <span class="text-muted">Kai_Ge</span>
<a class="tag" taget="_blank" href="/search/MyEclipse/1.htm">MyEclipse</a>
                                    <div>今天早上打开MyEclipse时,自动关闭!弹出An error has occurred.See the log file错误提示! 
很郁闷昨天启动和关闭还好着!!!打开几次依然报此错误,确定不是眼花了! 
打开日志文件!找到当日错误文件内容: 
--------------------------------------------------------------------------</div>
                                </li>
                                <li><a href="/article/2244.htm"
                                       title="[矿业与工业]修建一个空间矿床开采站要多少钱?" target="_blank">[矿业与工业]修建一个空间矿床开采站要多少钱?</a>
                                    <span class="text-muted">comsci</span>

                                    <div> 
       地球上的钛金属矿藏已经接近枯竭........... 
 
       我们在冥王星的一颗卫星上面发现一些具有开采价值的矿床..... 
 
       那么,现在要编制一个预算,提交给财政部门..</div>
                                </li>
                                <li><a href="/article/2371.htm"
                                       title="解析Google Map Routes" target="_blank">解析Google Map Routes</a>
                                    <span class="text-muted">dai_lm</span>
<a class="tag" taget="_blank" href="/search/google+api/1.htm">google api</a>
                                    <div>为了获得从A点到B点的路劲,经常会使用Google提供的API,例如 
[url] 
http://maps.googleapis.com/maps/api/directions/json?origin=40.7144,-74.0060&destination=47.6063,-122.3204&sensor=false 
[/url] 
从返回的结果上,大致可以了解应该怎么走,但</div>
                                </li>
                                <li><a href="/article/2498.htm"
                                       title="SQL还有多少“理所应当”?" target="_blank">SQL还有多少“理所应当”?</a>
                                    <span class="text-muted">datamachine</span>
<a class="tag" taget="_blank" href="/search/sql/1.htm">sql</a>
                                    <div>转贴存档,原帖地址:http://blog.chinaunix.net/uid-29242841-id-3968998.html、http://blog.chinaunix.net/uid-29242841-id-3971046.html! 
 
------------------------------------华丽的分割线-------------------------------- 
</div>
                                </li>
                                <li><a href="/article/2625.htm"
                                       title="Yii使用Ajax验证时,如何设置某些字段不需要验证" target="_blank">Yii使用Ajax验证时,如何设置某些字段不需要验证</a>
                                    <span class="text-muted">dcj3sjt126com</span>
<a class="tag" taget="_blank" href="/search/Ajax/1.htm">Ajax</a><a class="tag" taget="_blank" href="/search/yii/1.htm">yii</a>
                                    <div>经常像你注册页面,你可能非常希望只需要Ajax去验证用户名和Email,而不需要使用Ajax再去验证密码,默认如果你使用Yii 内置的ajax验证Form,例如: 
$form=$this->beginWidget('CActiveForm', array(        'id'=>'usuario-form',&</div>
                                </li>
                                <li><a href="/article/2752.htm"
                                       title="使用git同步网站代码" target="_blank">使用git同步网站代码</a>
                                    <span class="text-muted">dcj3sjt126com</span>
<a class="tag" taget="_blank" href="/search/crontab/1.htm">crontab</a><a class="tag" taget="_blank" href="/search/git/1.htm">git</a>
                                    <div>转自:http://ued.ctrip.com/blog/?p=3646?tn=gongxinjun.com 
  
管理一网站,最开始使用的虚拟空间,采用提供商支持的ftp上传网站文件,后换用vps,vps可以自己搭建ftp的,但是懒得搞,直接使用scp传输文件到服务器,现在需要更新文件到服务器,使用scp真的很烦。发现本人就职的公司,采用的git+rsync的方式来管理、同步代码,遂</div>
                                </li>
                                <li><a href="/article/2879.htm"
                                       title="sql基本操作" target="_blank">sql基本操作</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/sql%E5%9F%BA%E6%9C%AC%E6%93%8D%E4%BD%9C/1.htm">sql基本操作</a><a class="tag" taget="_blank" href="/search/sql%E5%B8%B8%E7%94%A8%E6%93%8D%E4%BD%9C/1.htm">sql常用操作</a>
                                    <div>sql基本操作 
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 
蕃薯耀 2015年6月1日 17:30:33 星期一 
  
  
&</div>
                                </li>
                                <li><a href="/article/3006.htm"
                                       title="Spring4+Hibernate4+Atomikos3.3多数据源事务管理" target="_blank">Spring4+Hibernate4+Atomikos3.3多数据源事务管理</a>
                                    <span class="text-muted">hanqunfeng</span>
<a class="tag" taget="_blank" href="/search/Hibernate4/1.htm">Hibernate4</a>
                                    <div>Spring3+后不再对JTOM提供支持,所以可以改用Atomikos管理多数据源事务。Spring2.5+Hibernate3+JTOM参考:http://hanqunfeng.iteye.com/blog/1554251Atomikos官网网站:http://www.atomikos.com/   一.pom.xml 
<dependency>
			<</div>
                                </li>
                                <li><a href="/article/3133.htm"
                                       title="jquery中两个值得注意的方法one()和trigger()方法" target="_blank">jquery中两个值得注意的方法one()和trigger()方法</a>
                                    <span class="text-muted">jackyrong</span>
<a class="tag" taget="_blank" href="/search/trigger/1.htm">trigger</a>
                                    <div>  在jquery中,有两个值得注意但容易忽视的方法,分别是one()方法和trigger()方法,这是从国内作者<<jquery权威指南》一书中看到不错的介绍 
 
 
1) one方法 
    one方法的功能是让所选定的元素绑定一个仅触发一次的处理函数,格式为 
   one(type,${data},fn) 
&nb</div>
                                </li>
                                <li><a href="/article/3260.htm"
                                       title="拿工资不仅仅是让你写代码的" target="_blank">拿工资不仅仅是让你写代码的</a>
                                    <span class="text-muted">lampcy</span>
<a class="tag" taget="_blank" href="/search/%E5%B7%A5%E4%BD%9C/1.htm">工作</a><a class="tag" taget="_blank" href="/search/%E9%9D%A2%E8%AF%95/1.htm">面试</a><a class="tag" taget="_blank" href="/search/%E5%92%A8%E8%AF%A2/1.htm">咨询</a>
                                    <div>这是我对团队每个新进员工说的第一件事情。这句话的意思是,我并不关心你是如何快速完成任务的,哪怕代码很差,只要它像救生艇通气门一样管用就行。这句话也是我最喜欢的座右铭之一。 
这个说法其实很合理:我们的工作是思考客户提出的问题,然后制定解决方案。思考第一,代码第二,公司请我们的最终目的不是写代码,而是想出解决方案。 
话粗理不粗。 
付你薪水不是让你来思考的,也不是让你来写代码的,你的目的是交付产品</div>
                                </li>
                                <li><a href="/article/3387.htm"
                                       title="架构师之对象操作----------对象的效率复制和判断是否全为空" target="_blank">架构师之对象操作----------对象的效率复制和判断是否全为空</a>
                                    <span class="text-muted">nannan408</span>
<a class="tag" taget="_blank" href="/search/%E6%9E%B6%E6%9E%84%E5%B8%88/1.htm">架构师</a>
                                    <div>1.前言。 
  如题。 
2.代码。 
 (1)对象的复制,比spring的beanCopier在大并发下效率要高,利用net.sf.cglib.beans.BeanCopier 
 

Src src=new Src();
BeanCopier beanCopier = BeanCopier.create(Src.class, Des.class, false);
      </div>
                                </li>
                                <li><a href="/article/3514.htm"
                                       title="ajax 被缓存的解决方案" target="_blank">ajax 被缓存的解决方案</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/jquery/1.htm">jquery</a><a class="tag" taget="_blank" href="/search/Ajax/1.htm">Ajax</a><a class="tag" taget="_blank" href="/search/cache/1.htm">cache</a><a class="tag" taget="_blank" href="/search/%E7%BC%93%E5%AD%98/1.htm">缓存</a>
                                    <div>使用jquery的ajax来发送请求进行局部刷新画面,各位可能都做过。 
今天碰到一个奇怪的现象,就是,同一个ajax请求,在chrome中,不论发送多少次,都可以发送至服务器端,而不会被缓存。但是,换成在IE下的时候,发现,同一个ajax请求,会发生被缓存的情况,只有第一次才会被发送至服务器端,之后的不会再被发送。郁闷。 
解决方法如下: 
① 直接使用 JQuery提供的 “cache”参数,</div>
                                </li>
                                <li><a href="/article/3641.htm"
                                       title="修改date.toLocaleString()的警告" target="_blank">修改date.toLocaleString()的警告</a>
                                    <span class="text-muted">tntxia</span>
<a class="tag" taget="_blank" href="/search/String/1.htm">String</a>
                                    <div>  
我们在写程序的时候,经常要查看时间,所以我们经常会用到date.toLocaleString(),但是date.toLocaleString()是一个过时 的API,代替的方法如下: 
  
package com.tntxia.htmlmaker.util;

import java.text.SimpleDateFormat;
import java.util.</div>
                                </li>
                                <li><a href="/article/3768.htm"
                                       title="项目完成后的小总结" target="_blank">项目完成后的小总结</a>
                                    <span class="text-muted">xiaomiya</span>
<a class="tag" taget="_blank" href="/search/js/1.htm">js</a><a class="tag" taget="_blank" href="/search/%E6%80%BB%E7%BB%93/1.htm">总结</a><a class="tag" taget="_blank" href="/search/%E9%A1%B9%E7%9B%AE/1.htm">项目</a>
                                    <div>项目完成了,突然想做个总结但是有点无从下手了。 
做之前对于客户端给的接口很模式。然而定义好了格式要求就如此的愉快了。 
先说说项目主要实现的功能吧 
1,按键精灵 
2,获取行情数据 
3,各种input输入条件判断 
4,发送数据(有json格式和string格式) 
5,获取预警条件列表和预警结果列表, 
6,排序, 
7,预警结果分页获取 
8,导出文件(excel,text等) 
9,修</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>