var d = new Date, count = 0, f, timer; timer = setInterval(f = function (){ if(new Date - d > 1000) { clearInterval(timer), console.log(count); } count++; }, 0);
try{ setTimeout(function(){ throw new Error("我不但愿这个错误出现!") }, 1000); } catch(e){ console.log(e.message); }
function getData(callback) { $.ajax({ url: '', success: resp => { callback(resp); } }); } getData(resp => { // write your code here });
function getData(callback) { $.ajax({ url: '', success: resp => { callback(resp.data); callback.bind(null)(resp.data); callback.call(null, resp.data); callback.apply(null, resp.data); } }); } getData((...resp) => { // write your code here });
let myEvents = new MyEvent(); myEvents.addEvents({ once: () => { console.log('只会console一次'); myEvents.removeEvent('once'); }, infinity: () => { console.log('每次点击,都会console'); } }); document.onclick = e => { myEvents.fireEvents(['once', 'infinity']); }
let elImage = document.getElementById('image'); $(elImage).addEvent('click', e => { e = e || window.event; let target = e.target || e.srcElement; // 元素节点 为1; 元素属性 为2 if (target.nodeType === 1) { console.log(`点击类型:${e.type}`); $(target).fireEvent('console'); } })
let subPub = new SubPub(); subPub.subscribe('getName', name => { console.log('your name is: ', name); }); subPub.publish('getName', 'Tom');
1.观察者模式和发布/订阅的区别:
1.1.Observer模式要求但愿接收到主题通知者的观察者必须订阅内容改变的事件
1.2.Subscribe/Publish模式使用了一个主题/事件通道,这个通道介于订阅者和发布者之间。该事件系统容许代码定义应用程序的特定事件,该事件能够传递自定义参数,自定义参数包含订阅者所须要的值。其目的是避免订阅者和发布者产生依赖关系。
from: 《Javascript设计模式》
vue
const EventEmitter = require('events'); class MyEmitter extends EventEmitter {} const myEmitter = new MyEmitter(); myEmitter.on('event', (a, b) => { console.log(a, b, this); }); myEmitter.emit('event', 'a', 'b');
2.1.ES6中import对于循环引用的处理问题java
TODO: require引用?node
2.2.?commonJS中require是值的copy?,ES6中import是值的引用react
doSomething().then(function () { return doSomethingElse(); }).then(finalHandler); doSomething().then(function () { doSomethingElse(); }).then(finalHandler); doSomething().then(doSomethingElse()).then(finalHandler); doSomething().then(doSomethingElse).then(finalHandler);
// 不推荐 somePromise() .then(data => { anotherPromise() .then(anotherData => { // write your code here }) .catch(window.console.log.bind(window.console)) }) .catch(window.console.log.bind(window.console)) // 推荐 somePromise() .then(data => { return anotherPromise().then(data, anotherData); }) then((data, another) => { }) .catch(window.console.log.bind(window.console))
let promises = [new Promise(resolve => { let dataA = { name: 'dataA' }; resolve(dataA); }), new Promise(resolve => { let dataB = { name: 'dataB' }; resolve(dataB); })]; let keys = ['dataA', 'dataB'] let dataAll = {}; promises.forEach((promise, index) => { promise .then(data => { dataAll[keys[index]] = data; }) .catch(e => { console.log('error: ', e); }) });
somePromise() .then(() => { return anotherPromise(); }) .then(() => { return lastPromise(); }) // 没有业务错误需求,加上这句就方便调试 .catch(console.log.bind(console));
4.2.3.不推荐使用deferred(历史包袱),两种方式改正es6
4.2.3.1.使用第三方的库包装成promise,如angular的$q库:github
$q.when(db.put(doc)).then(...)
new Promise(function (resolve, reject) { fs.readFile('myfile.txt', function (err, file) { if (err) { return reject(err); } resolve(file); }); }) .then(...)
somePromise() .then(() => { anotherPromise(); }) .then(data => { // data was undefined })
// 1.then reject somePromise().then(resolve => { throw new Error('error'); }, reject => { // catch nothing }) // 2.catch: this type was recomended somePromise() .then(resolve => { throw new Error('error'); }) .catch(e => { // catch the error }) // 3.the same as below: somePromise() .then(resolve => { throw new Error('error'); }) .then(null, e => { // catch the error })
function executeSequentially(promiseFactories) { var result = Promise.resolve(); promiseFactories.forEach(function (promiseFactory) { result = result.then(promiseFactory); }); return result; } // 使用promise工厂 function myPromiseFactory() { return somethingThatCreatesAPromise(); } // 示例: let promiseFactories = []; promiseFactories.push(myPromiseFactory); executeSequentially(promiseFactories);
4.3.4.想要两个promise的结果ajax
4.3.4.1.原始代码
let getUserAndAccount = user => { return new Promise((resolve, reject) => { getUserAccountById(user.id) .then(userAccount => { resolve(user, userAccount); }) .catch(reject); }) } getUserByName('nolan') .then(getUserAndAccount) .then(function (user, userAccount) { console.log('user and userAccount: ', user, userAccount); }) .cath(e => { console.log('error: ', e); });
let getUserAndAccount = user => getUserAccountById(user.id) .then(userAccount => Promise.resolve(user, userAccount)) getUserByName('nolan') .then(getUserAndAccount) .then(function (user, userAccount) { console.log('user and userAccount: ', user, userAccount); }) .cath(e => { console.log('error: ', e); });
Promise.resolve('foo').then(Promise.resolve('bar')).then(function (result) { console.log(result); });
return
一个promise对象。return
一个同步值或者是undefinedthrow
一个错误getUserByName('nolan').then(function (user) { if (user.isLoggedOut()) { throw new Error('user logged out!'); // throwing a synchronous error! } return inMemoryCache[user.id] || getUserAccountById(user.id); // returning a synchronous value or a promise! }).then(function (userAccount) { // I got a user account! }).catch(function (err) { // Boo, I got an error! if (err) { let message = err.message; if (~message.indexOf('logged')) { // 已经登出的处理逻辑 } else { // 其余的错误处理逻辑 } } });
Promise.all([new Promise((resolve, reject) => { setTimeout(() => { console.log('first'); }, 1000); }), Promise.reject(123), new Promise((resolve, reject) => { console.log('second'); resolve(); })]) .then(data => { console.log('I am all data: ', data); }) .catch(e => { console.log('error', e); });
let timeout = 3e3; Promise.race([new Promise((resolve, reject) => { $.ajax('url', resp => { console.log('ajax resp: ', resp); }); }), new Promise((resolve, reject) => { setTimeout(resolve, timeout); })]);
6.2.Promise.resolve返回一个已经resolve的promise对象,reject同理
function* gen(){ let url = 'https://api.github.com/users/github'; let result = yield fetch(url); console.log('result: ', result.bio); } let genUser = () => { let g = gen(); let result = g.next(); result.value.then(data => { let json = data.json(); return json; }).then(data => { g.next(data); }); }
1.1.函数能够暂停执行和恢复执行
1.2.Generator 函数能够不用yield表达式,这时就变成了一个单纯的暂缓执行函数
function* f() { console.log('执行了!') } var generator = f(); setTimeout(function () { generator.next() }, 2000);
function* gen(x){ var y = yield x + 2; console.log('gen(): ', y, x); return y; } var g = gen(1); var value = g.next(); console.log('value: ', value); var value2 = g.next(12); console.log('value2: ', value2);
function f(param) { let a = yield 3 * param; }
var gen = function* (){ var f1 = yield readFile('fileA'); var f2 = yield readFile('fileB'); // ... var fn = yield readFile('fileN'); }; run(gen);
2.thunk函数介绍: 诞生于上个60年代
2.1.1.传值调用
let f = (a, b) => b; f(3 * x * x - 2 * x - 1, x);
let f = m => m * 2; f(x + 5); 60年代就诞生 // 等同于 let thunk () => (x + 5); let f = thunk => (thunk() * 2);
function thunkify(fn){ return function(){ let args = Array.prototype.slice.call(arguments); let ctx = this; return function(done){ // 检查机制: 确保回调函数只运行一次 let called; args.push(function(){ if (called) return; called = true; done.apply(null, arguments); }); try { fn.apply(ctx, args); } catch (err) { done(err); } } } };
let fs = require('fs'); let thunkify = require('thunkify'); let readFile = thunkify(fs.readFile); let gen = function* (){ let r1 = yield readFile('/etc/fstab'); console.log(r1.toString()); let r2 = yield readFile('/etc/shells'); console.log(r2.toString()); };
let g = gen(); let r1 = g.next(); r1.value(function(err, data){ if (err) throw err; let r2 = g.next(data); r2.value(function(err, data){ if (err) throw err; g.next(data); }); });
function run(fn) { let gen = fn(); function next(err, data) { let result = gen.next(data); if (result.done) return; result.value(next); } next(); } run(gen);
var gen = function* (){ var f1 = yield readFile('/etc/fstab'); var f2 = yield readFile('/etc/shells'); console.log(f1.toString()); console.log(f2.toString()); }; var co = require('co'); co(gen);
3.1.协程与事件循环: 控制流的主动让出和恢复
3.1.1.提出时间: 1963; 提出人: Melvin Conway
3.1.2.历程: 进程->线程->用户态线程->协程
3.1.3.3.用户态线程: 线程切换的时候,进程须要为了管理而切换到内核态,处理状态转换(性能消耗严重)
3.1.5.关系: 子历程是没有使用yield的协程。Donald Ervin Knuth(wiki)/Donald Ervin Knuth(baidu): 子历程是协程的一种特例
3.2.没有异常处理的简化版co函数
function co(gen){ let def = Promise.defer(); let iter = gen(); function resolve(data) { // 恢复迭代器并带入promise的终值 step(iter.next(data)); } function step(it) { it.done ? // 迭代结束则解决co返回的promise def.resolve(it.value) : // 不然继续用解决程序解决下一个让步出来的promise it.value.then(resolve); } resolve(); return def.promise; }
let getData = () => { return new Promise((resolve, reject) => { $.ajax({ url: 'json/test.json', method: 'GET', success: function (resp) { // data = resp.data; resolve(resp); }, error: function (error) { reject(error); } }); }); } async function initView(){ try { let resp = await getData(); console.log(resp); } catch (e) { console.error(e); } } initView();
1.同时触发:
// 写法一 let [foo, bar] = await Promise.all([getFoo(), getBar()]); // 写法二 let fooPromise = getFoo(); let barPromise = getBar(); let foo = await fooPromise; let bar = await barPromise;
1.从异步操做上,async是最后演化的结果,callback是就不用了、仍是应该尽可能避免?