这个未定义:可能异步到生成器问题
this undefined: possible async to generator issue
我从我用于 firebase 休息事务的库中获取 'client' undefined
,我很确定我以前使用过它没有问题。当我查看库时(intellij websphere 调试器将我带到一个打字稿文件,必须是地图感知的),我看到 this.client
...,在我调用的 class 方法中,所以这个应该肯定被定义。
然后我抓取了一个不同的库,它恰好是一个文件,所以我可以将它直接放在我的 src/ 文件夹中,(当周围有其他破损的轮子时,为什么要修复一个平面,对吧?)和.. 同样的事情(只是这次是 this.url
因为图书馆不同)。
基本结构 确实 有效,因为:(将注释代码与内联 Promise 进行比较)
class FirebaseDb {
constructor() {}
async tx(command, path, payload, queryParams) {
const dbcmd = FirebaseDb.ref[FirebaseDb.fbcrest[command]]
/*const unary = (command === 'get' || commmand === 'delete')
const operation = await (unary?
dbcmd(path, queryParams):
dbcmd(path, payload, queryParams))*/
const res = await new Promise((r,e)=>setTimeout(
()=>{
console.log('inner this: ' + this);
r({foo:'bar'})
}, 1000))
const operation = {ok: true, body: res}
if(!operation.ok)
throw new Error(`[FirebaseDb] ${FirebaseDb.fbcrest[command]} - error with TX. (status ${operation.status}: ${operation.statusText})`)
return operation.body
}
这个承诺很好用。我点击 api url 并在一秒钟后得到 {"foo":"bar"}
。控制台不显示 undefined
this
,它报告 inner this: [object Object]
.
所以这是完整的两个文件(该片段来自firebaseDb.js,因为它只是一个演示,所以不会在下面显示):
firebaseDb.js
import restFirebase from './restful-firebase'
import config from 'config'
/* FirebaseDb is a specific Model Db Firebase object. It receives REST calls
and converts them to firebase REST calls, executes them on a firebase
connection, returning the result or erroring out if there is an error. this
could be swapped out with a similar one for MongoDB, etc */
class FirebaseDb {
constructor() {}
async tx(command, path, payload, queryParams) {
const dbcmd = FirebaseDb.ref[FirebaseDb.fbcrest[command]]
const unary = (command === 'get' || commmand === 'delete')
const operation = await (unary?
dbcmd(path, queryParams):
dbcmd(path, payload, queryParams))
if(!operation.ok)
throw new Error(`[FirebaseDb] ${FirebaseDb.fbcrest[command]} - error with TX. (status ${operation.status}: ${operation.statusText})`)
return operation.body
}
}
FirebaseDb.fbcrest = {
get: 'get',
put: 'set',
patch: 'update',
post: 'push',
delete: 'remove'
}
FirebaseDb.db = restFirebase.factory(config.firebase.project)
FirebaseDb.ref = FirebaseDb.db({
paths: '/',
auth: config.firebase.auth
})
export default FirebaseDb
restful-firebase.js
(修改了 npm i rest-firebase,在 tx 调用中接受路径,不使用 strict 进行调试):
import request from 'request'
const TIMEOUT = 5000;
const baseRequest = request.defaults({timeout: TIMEOUT, json: true});
const VALID_ID = /^[-0-9a-zA-Z]{2,}$/;
const VALID_URL = /^https?:\/\/[\da-z\.-]+(\:\d+)?\/?$/;
const ERR_INVALID_ID = 'Invalid Firebase id.';
const ERR_NO_SECRET = 'A Firebase secret is required for this operation.';
class ResponseError extends Error {
constructor(opts, resp, body) {
super(resp.statusMessage);
this.name = 'ResponseError';
this.url = opts.url;
this.method = opts.method;
this.status = resp.statusCode;
this.authDebug = resp.headers['x-firebase-auth-debug'];
this.body = body;
}
}
class Request {
constructor(opts) {
this.rootPath = trimPath(opts.rootPath);
this.url = opts.url;
this.auth = opts.auth;
this.$logger = opts.logger || console;
}
toString() {
return Request.fixUrl(this.url);
}
static fixUrl(url) {
return url.endsWith('.json') ? url : `${url}.json`;
}
process(url, method, qs, payload) {
return new Promise((resolve, reject) => {
const opts = {
url: Request.fixUrl(url),
method: method,
qs: Object.assign({auth: this.auth}, qs)
};
if (payload !== undefined) {
opts.body = payload;
}
baseRequest(opts, (err, resp, body) => {
if (err) {
reject(err);
return;
}
const debugMessage = resp.headers['x-firebase-auth-debug'];
if (debugMessage) {
this.$logger.warn(debugMessage);
}
if (resp.statusCode >= 300) {
reject(new ResponseError(opts, resp, body));
return;
}
resolve(body);
});
});
}
rules(rules) {
if (!this.auth) {
return Promise.reject(new Error(ERR_NO_SECRET));
}
const opts = {
'method': 'GET',
'url': `${this.rootPath}/.settings/rules.json`,
'qs': {auth: this.auth}
};
return new Promise((resolve, reject) => {
if (rules) {
opts.method = 'PUT';
opts.body = rules;
opts.json = typeof(rules) === 'object';
}
request(opts, (err, resp, body) => {
if (err) {
reject(err);
return;
}
if (resp.statusCode >= 300) {
reject(new ResponseError(opts, resp, body));
return;
}
resolve(body);
});
});
}
get(path, qs) {
let url = this.url
if(path)
url += '/' + path
return this.process(url, 'GET', qs);
}
set(path, payload, qs) {
let url = this.url
if(path)
url += '/' + path
return this.process(url, 'PUT', qs, payload);
}
update(path, payload, qs) {
let url = this.url
if(path)
url += '/' + path
if (url.endsWith('/.json')) {
// no-op
} else if (url.endsWith('.json')) {
url = `${url.slice(0, -5)}/.json`;
} else if (url.endsWith('/')) {
url = `${url}.json`;
} else {
url = `${url}/.json`;
}
return this.process(url, 'PATCH', qs, payload);
}
push(path, patch, qs) {
let url = this.url
if(path)
url += '/' + path
return this.process(url, 'POST', qs, patch);
}
remove(path, qs) {
let url = this.url
if(path)
url += '/' + path
return this.process(url, 'DELETE', qs);
}
}
function trimPath(path) {
return path.replace(/\/+$/, '');
}
/**
* Create a firebase rest client factory.
*
* The clients will be bound to a firebase ID. You then can use relative path
* to create references to entities in your Firebase DB.
*
* Usage:
*
* const restFirebase = require('rest-firebase');
* const firebase = restFirebase.factory('some-id');
* const ref = firebase({paths: 'some/path', auth: 'some-oauth-token'});
*
* // you can pass parameters
* // (see https://www.firebase.com/docs/rest/api/#section-query-parameters)
* ref.get({shallow: true}).then(value => {
* // ...
* });
*
* @param {string} target Firebase ID or URL
* @return {function}
*
*/
function restFirebaseFactory(target) {
let rootPath;
if (VALID_URL.test(target)) {
rootPath = trimPath(target);
} else if (VALID_ID.test(target)) {
rootPath = `https://${target}.firebaseio.com`;
} else {
throw new Error(ERR_INVALID_ID);
}
function restFirebase(opts) {
const relPaths = opts && opts.paths || '';
const url = [rootPath].concat(relPaths).join('/');
return new Request(
Object.assign({}, opts, {rootPath, url})
);
}
return restFirebase;
}
exports.Request = Request;
exports.factory = restFirebaseFactory;
可能涉及的一些"magic":
我的.babelrc
{
"presets": ["latest"]
}
我的 gulpfile:
const gulp = require('gulp');
const babel = require('gulp-babel');
const clean = require('gulp-rimraf');
const dest = 'dist'
gulp.task('src', ['clean'], () => {
return gulp.src(['server.js', 'src/**/*.js'])
.pipe(babel({
plugins: ['syntax-async-functions','transform-async-to-generator', 'transform-runtime']
}))
.pipe(gulp.dest(dest));
});
gulp.task('node_modules', ['clean', 'src'], () => {
return gulp.src(['node_modules/vue/dist/vue.js', 'node_modules/vue-router/dist/vue-router.js', 'node_modules/vuex/dist/vuex.js'])
.pipe(gulp.dest(dest+'/node_modules'));
});
gulp.task('clean', () => {
gulp.src(dest+'/*', {read:false})
.pipe(clean())
})
gulp.task('default', ['node_modules', 'src'])
这样做是为了 restful-firebase.js:
'use strict';
var _typeof2 = require('babel-runtime/helpers/typeof');
var _typeof3 = _interopRequireDefault(_typeof2);
var _assign = require('babel-runtime/core-js/object/assign');
var _assign2 = _interopRequireDefault(_assign);
var _promise = require('babel-runtime/core-js/promise');
var _promise2 = _interopRequireDefault(_promise);
var _createClass2 = require('babel-runtime/helpers/createClass');
var _createClass3 = _interopRequireDefault(_createClass2);
var _getPrototypeOf = require('babel-runtime/core-js/object/get-prototype-of');
var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf);
var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck');
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn');
var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
var _inherits2 = require('babel-runtime/helpers/inherits');
var _inherits3 = _interopRequireDefault(_inherits2);
var _request = require('request');
var _request2 = _interopRequireDefault(_request);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var TIMEOUT = 5000;
var baseRequest = _request2.default.defaults({ timeout: TIMEOUT, json: true });
var VALID_ID = /^[-0-9a-zA-Z]{2,}$/;
var VALID_URL = /^https?:\/\/[\da-z\.-]+(\:\d+)?\/?$/;
var ERR_INVALID_ID = 'Invalid Firebase id.';
var ERR_NO_SECRET = 'A Firebase secret is required for this operation.';
var ResponseError = function (_Error) {
(0, _inherits3.default)(ResponseError, _Error);
function ResponseError(opts, resp, body) {
(0, _classCallCheck3.default)(this, ResponseError);
var _this = (0, _possibleConstructorReturn3.default)(this, (ResponseError.__proto__ || (0, _getPrototypeOf2.default)(ResponseError)).call(this, resp.statusMessage));
_this.name = 'ResponseError';
_this.url = opts.url;
_this.method = opts.method;
_this.status = resp.statusCode;
_this.authDebug = resp.headers['x-firebase-auth-debug'];
_this.body = body;
return _this;
}
return ResponseError;
}(Error);
var Request = function () {
function Request(opts) {
(0, _classCallCheck3.default)(this, Request);
this.rootPath = trimPath(opts.rootPath);
this.url = opts.url;
this.auth = opts.auth;
this.$logger = opts.logger || console;
}
(0, _createClass3.default)(Request, [{
key: 'toString',
value: function toString() {
return Request.fixUrl(this.url);
}
}, {
key: 'process',
value: function process(url, method, qs, payload) {
var _this2 = this;
return new _promise2.default(function (resolve, reject) {
var opts = {
url: Request.fixUrl(url),
method: method,
qs: (0, _assign2.default)({ auth: _this2.auth }, qs)
};
if (payload !== undefined) {
opts.body = payload;
}
baseRequest(opts, function (err, resp, body) {
if (err) {
reject(err);
return;
}
var debugMessage = resp.headers['x-firebase-auth-debug'];
if (debugMessage) {
_this2.$logger.warn(debugMessage);
}
if (resp.statusCode >= 300) {
reject(new ResponseError(opts, resp, body));
return;
}
resolve(body);
});
});
}
}, {
key: 'rules',
value: function rules(_rules) {
if (!this.auth) {
return _promise2.default.reject(new Error(ERR_NO_SECRET));
}
var opts = {
'method': 'GET',
'url': this.rootPath + '/.settings/rules.json',
'qs': { auth: this.auth }
};
return new _promise2.default(function (resolve, reject) {
if (_rules) {
opts.method = 'PUT';
opts.body = _rules;
opts.json = (typeof _rules === 'undefined' ? 'undefined' : (0, _typeof3.default)(_rules)) === 'object';
}
(0, _request2.default)(opts, function (err, resp, body) {
if (err) {
reject(err);
return;
}
if (resp.statusCode >= 300) {
reject(new ResponseError(opts, resp, body));
return;
}
resolve(body);
});
});
}
}, {
key: 'get',
value: function get(path, qs) {
var url = this.url;
if (path) url += '/' + path;
return this.process(url, 'GET', qs);
}
}, {
key: 'set',
value: function set(path, payload, qs) {
var url = this.url;
if (path) url += '/' + path;
return this.process(url, 'PUT', qs, payload);
}
}, {
key: 'update',
value: function update(path, payload, qs) {
var url = this.url;
if (path) url += '/' + path;
if (url.endsWith('/.json')) {
// no-op
} else if (url.endsWith('.json')) {
url = url.slice(0, -5) + '/.json';
} else if (url.endsWith('/')) {
url = url + '.json';
} else {
url = url + '/.json';
}
return this.process(url, 'PATCH', qs, payload);
}
}, {
key: 'push',
value: function push(path, patch, qs) {
var url = this.url;
if (path) url += '/' + path;
return this.process(url, 'POST', qs, patch);
}
}, {
key: 'remove',
value: function remove(path, qs) {
var url = this.url;
if (path) url += '/' + path;
return this.process(url, 'DELETE', qs);
}
}], [{
key: 'fixUrl',
value: function fixUrl(url) {
return url.endsWith('.json') ? url : url + '.json';
}
}]);
return Request;
}();
function trimPath(path) {
return path.replace(/\/+$/, '');
}
/**
* Create a firebase rest client factory.
*
* The clients will be bound to a firebase ID. You then can use relative path
* to create references to entities in your Firebase DB.
*
* Usage:
*
* const restFirebase = require('rest-firebase');
* const firebase = restFirebase.factory('some-id');
* const ref = firebase({paths: 'some/path', auth: 'some-oauth-token'});
*
* // you can pass parameters
* // (see https://www.firebase.com/docs/rest/api/#section-query-parameters)
* ref.get({shallow: true}).then(value => {
* // ...
* });
*
* @param {string} target Firebase ID or URL
* @return {function}
*
*/
function restFirebaseFactory(target) {
var rootPath = void 0;
if (VALID_URL.test(target)) {
rootPath = trimPath(target);
} else if (VALID_ID.test(target)) {
rootPath = 'https://' + target + '.firebaseio.com';
} else {
throw new Error(ERR_INVALID_ID);
}
function restFirebase(opts) {
var relPaths = opts && opts.paths || '';
var url = [rootPath].concat(relPaths).join('/');
return new Request((0, _assign2.default)({}, opts, { rootPath: rootPath, url: url }));
}
return restFirebase;
}
exports.Request = Request;
exports.factory = restFirebaseFactory;
特别是 this
未定义的代码部分,抛出错误的是第 3 行:
key: 'get',
value: function get(path, qs) {
var url = this.url;
if (path) url += '/' + path;
return this.process(url, 'GET', qs);
}
通常假设在这种情况下该方法被调用为回调是安全的,这可以通过使用箭头函数或 bind
来解决。如果对象方法未绑定,则不能从对象中分离出来。
考虑到
const dbcmd = FirebaseDb.ref[FirebaseDb.fbcrest[command]]
是名胜,应该是
const dbcmd = FirebaseDb.ref[FirebaseDb.fbcrest[command]].bind(FirebaseDb.ref)
或
const dbcmd = (...args) => FirebaseDb.ref[FirebaseDb.fbcrest[command]](...args)
我从我用于 firebase 休息事务的库中获取 'client' undefined
,我很确定我以前使用过它没有问题。当我查看库时(intellij websphere 调试器将我带到一个打字稿文件,必须是地图感知的),我看到 this.client
...,在我调用的 class 方法中,所以这个应该肯定被定义。
然后我抓取了一个不同的库,它恰好是一个文件,所以我可以将它直接放在我的 src/ 文件夹中,(当周围有其他破损的轮子时,为什么要修复一个平面,对吧?)和.. 同样的事情(只是这次是 this.url
因为图书馆不同)。
基本结构 确实 有效,因为:(将注释代码与内联 Promise 进行比较)
class FirebaseDb {
constructor() {}
async tx(command, path, payload, queryParams) {
const dbcmd = FirebaseDb.ref[FirebaseDb.fbcrest[command]]
/*const unary = (command === 'get' || commmand === 'delete')
const operation = await (unary?
dbcmd(path, queryParams):
dbcmd(path, payload, queryParams))*/
const res = await new Promise((r,e)=>setTimeout(
()=>{
console.log('inner this: ' + this);
r({foo:'bar'})
}, 1000))
const operation = {ok: true, body: res}
if(!operation.ok)
throw new Error(`[FirebaseDb] ${FirebaseDb.fbcrest[command]} - error with TX. (status ${operation.status}: ${operation.statusText})`)
return operation.body
}
这个承诺很好用。我点击 api url 并在一秒钟后得到 {"foo":"bar"}
。控制台不显示 undefined
this
,它报告 inner this: [object Object]
.
所以这是完整的两个文件(该片段来自firebaseDb.js,因为它只是一个演示,所以不会在下面显示):
firebaseDb.js
import restFirebase from './restful-firebase'
import config from 'config'
/* FirebaseDb is a specific Model Db Firebase object. It receives REST calls
and converts them to firebase REST calls, executes them on a firebase
connection, returning the result or erroring out if there is an error. this
could be swapped out with a similar one for MongoDB, etc */
class FirebaseDb {
constructor() {}
async tx(command, path, payload, queryParams) {
const dbcmd = FirebaseDb.ref[FirebaseDb.fbcrest[command]]
const unary = (command === 'get' || commmand === 'delete')
const operation = await (unary?
dbcmd(path, queryParams):
dbcmd(path, payload, queryParams))
if(!operation.ok)
throw new Error(`[FirebaseDb] ${FirebaseDb.fbcrest[command]} - error with TX. (status ${operation.status}: ${operation.statusText})`)
return operation.body
}
}
FirebaseDb.fbcrest = {
get: 'get',
put: 'set',
patch: 'update',
post: 'push',
delete: 'remove'
}
FirebaseDb.db = restFirebase.factory(config.firebase.project)
FirebaseDb.ref = FirebaseDb.db({
paths: '/',
auth: config.firebase.auth
})
export default FirebaseDb
restful-firebase.js
(修改了 npm i rest-firebase,在 tx 调用中接受路径,不使用 strict 进行调试):
import request from 'request'
const TIMEOUT = 5000;
const baseRequest = request.defaults({timeout: TIMEOUT, json: true});
const VALID_ID = /^[-0-9a-zA-Z]{2,}$/;
const VALID_URL = /^https?:\/\/[\da-z\.-]+(\:\d+)?\/?$/;
const ERR_INVALID_ID = 'Invalid Firebase id.';
const ERR_NO_SECRET = 'A Firebase secret is required for this operation.';
class ResponseError extends Error {
constructor(opts, resp, body) {
super(resp.statusMessage);
this.name = 'ResponseError';
this.url = opts.url;
this.method = opts.method;
this.status = resp.statusCode;
this.authDebug = resp.headers['x-firebase-auth-debug'];
this.body = body;
}
}
class Request {
constructor(opts) {
this.rootPath = trimPath(opts.rootPath);
this.url = opts.url;
this.auth = opts.auth;
this.$logger = opts.logger || console;
}
toString() {
return Request.fixUrl(this.url);
}
static fixUrl(url) {
return url.endsWith('.json') ? url : `${url}.json`;
}
process(url, method, qs, payload) {
return new Promise((resolve, reject) => {
const opts = {
url: Request.fixUrl(url),
method: method,
qs: Object.assign({auth: this.auth}, qs)
};
if (payload !== undefined) {
opts.body = payload;
}
baseRequest(opts, (err, resp, body) => {
if (err) {
reject(err);
return;
}
const debugMessage = resp.headers['x-firebase-auth-debug'];
if (debugMessage) {
this.$logger.warn(debugMessage);
}
if (resp.statusCode >= 300) {
reject(new ResponseError(opts, resp, body));
return;
}
resolve(body);
});
});
}
rules(rules) {
if (!this.auth) {
return Promise.reject(new Error(ERR_NO_SECRET));
}
const opts = {
'method': 'GET',
'url': `${this.rootPath}/.settings/rules.json`,
'qs': {auth: this.auth}
};
return new Promise((resolve, reject) => {
if (rules) {
opts.method = 'PUT';
opts.body = rules;
opts.json = typeof(rules) === 'object';
}
request(opts, (err, resp, body) => {
if (err) {
reject(err);
return;
}
if (resp.statusCode >= 300) {
reject(new ResponseError(opts, resp, body));
return;
}
resolve(body);
});
});
}
get(path, qs) {
let url = this.url
if(path)
url += '/' + path
return this.process(url, 'GET', qs);
}
set(path, payload, qs) {
let url = this.url
if(path)
url += '/' + path
return this.process(url, 'PUT', qs, payload);
}
update(path, payload, qs) {
let url = this.url
if(path)
url += '/' + path
if (url.endsWith('/.json')) {
// no-op
} else if (url.endsWith('.json')) {
url = `${url.slice(0, -5)}/.json`;
} else if (url.endsWith('/')) {
url = `${url}.json`;
} else {
url = `${url}/.json`;
}
return this.process(url, 'PATCH', qs, payload);
}
push(path, patch, qs) {
let url = this.url
if(path)
url += '/' + path
return this.process(url, 'POST', qs, patch);
}
remove(path, qs) {
let url = this.url
if(path)
url += '/' + path
return this.process(url, 'DELETE', qs);
}
}
function trimPath(path) {
return path.replace(/\/+$/, '');
}
/**
* Create a firebase rest client factory.
*
* The clients will be bound to a firebase ID. You then can use relative path
* to create references to entities in your Firebase DB.
*
* Usage:
*
* const restFirebase = require('rest-firebase');
* const firebase = restFirebase.factory('some-id');
* const ref = firebase({paths: 'some/path', auth: 'some-oauth-token'});
*
* // you can pass parameters
* // (see https://www.firebase.com/docs/rest/api/#section-query-parameters)
* ref.get({shallow: true}).then(value => {
* // ...
* });
*
* @param {string} target Firebase ID or URL
* @return {function}
*
*/
function restFirebaseFactory(target) {
let rootPath;
if (VALID_URL.test(target)) {
rootPath = trimPath(target);
} else if (VALID_ID.test(target)) {
rootPath = `https://${target}.firebaseio.com`;
} else {
throw new Error(ERR_INVALID_ID);
}
function restFirebase(opts) {
const relPaths = opts && opts.paths || '';
const url = [rootPath].concat(relPaths).join('/');
return new Request(
Object.assign({}, opts, {rootPath, url})
);
}
return restFirebase;
}
exports.Request = Request;
exports.factory = restFirebaseFactory;
可能涉及的一些"magic":
我的.babelrc
{
"presets": ["latest"]
}
我的 gulpfile:
const gulp = require('gulp');
const babel = require('gulp-babel');
const clean = require('gulp-rimraf');
const dest = 'dist'
gulp.task('src', ['clean'], () => {
return gulp.src(['server.js', 'src/**/*.js'])
.pipe(babel({
plugins: ['syntax-async-functions','transform-async-to-generator', 'transform-runtime']
}))
.pipe(gulp.dest(dest));
});
gulp.task('node_modules', ['clean', 'src'], () => {
return gulp.src(['node_modules/vue/dist/vue.js', 'node_modules/vue-router/dist/vue-router.js', 'node_modules/vuex/dist/vuex.js'])
.pipe(gulp.dest(dest+'/node_modules'));
});
gulp.task('clean', () => {
gulp.src(dest+'/*', {read:false})
.pipe(clean())
})
gulp.task('default', ['node_modules', 'src'])
这样做是为了 restful-firebase.js:
'use strict';
var _typeof2 = require('babel-runtime/helpers/typeof');
var _typeof3 = _interopRequireDefault(_typeof2);
var _assign = require('babel-runtime/core-js/object/assign');
var _assign2 = _interopRequireDefault(_assign);
var _promise = require('babel-runtime/core-js/promise');
var _promise2 = _interopRequireDefault(_promise);
var _createClass2 = require('babel-runtime/helpers/createClass');
var _createClass3 = _interopRequireDefault(_createClass2);
var _getPrototypeOf = require('babel-runtime/core-js/object/get-prototype-of');
var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf);
var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck');
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn');
var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
var _inherits2 = require('babel-runtime/helpers/inherits');
var _inherits3 = _interopRequireDefault(_inherits2);
var _request = require('request');
var _request2 = _interopRequireDefault(_request);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var TIMEOUT = 5000;
var baseRequest = _request2.default.defaults({ timeout: TIMEOUT, json: true });
var VALID_ID = /^[-0-9a-zA-Z]{2,}$/;
var VALID_URL = /^https?:\/\/[\da-z\.-]+(\:\d+)?\/?$/;
var ERR_INVALID_ID = 'Invalid Firebase id.';
var ERR_NO_SECRET = 'A Firebase secret is required for this operation.';
var ResponseError = function (_Error) {
(0, _inherits3.default)(ResponseError, _Error);
function ResponseError(opts, resp, body) {
(0, _classCallCheck3.default)(this, ResponseError);
var _this = (0, _possibleConstructorReturn3.default)(this, (ResponseError.__proto__ || (0, _getPrototypeOf2.default)(ResponseError)).call(this, resp.statusMessage));
_this.name = 'ResponseError';
_this.url = opts.url;
_this.method = opts.method;
_this.status = resp.statusCode;
_this.authDebug = resp.headers['x-firebase-auth-debug'];
_this.body = body;
return _this;
}
return ResponseError;
}(Error);
var Request = function () {
function Request(opts) {
(0, _classCallCheck3.default)(this, Request);
this.rootPath = trimPath(opts.rootPath);
this.url = opts.url;
this.auth = opts.auth;
this.$logger = opts.logger || console;
}
(0, _createClass3.default)(Request, [{
key: 'toString',
value: function toString() {
return Request.fixUrl(this.url);
}
}, {
key: 'process',
value: function process(url, method, qs, payload) {
var _this2 = this;
return new _promise2.default(function (resolve, reject) {
var opts = {
url: Request.fixUrl(url),
method: method,
qs: (0, _assign2.default)({ auth: _this2.auth }, qs)
};
if (payload !== undefined) {
opts.body = payload;
}
baseRequest(opts, function (err, resp, body) {
if (err) {
reject(err);
return;
}
var debugMessage = resp.headers['x-firebase-auth-debug'];
if (debugMessage) {
_this2.$logger.warn(debugMessage);
}
if (resp.statusCode >= 300) {
reject(new ResponseError(opts, resp, body));
return;
}
resolve(body);
});
});
}
}, {
key: 'rules',
value: function rules(_rules) {
if (!this.auth) {
return _promise2.default.reject(new Error(ERR_NO_SECRET));
}
var opts = {
'method': 'GET',
'url': this.rootPath + '/.settings/rules.json',
'qs': { auth: this.auth }
};
return new _promise2.default(function (resolve, reject) {
if (_rules) {
opts.method = 'PUT';
opts.body = _rules;
opts.json = (typeof _rules === 'undefined' ? 'undefined' : (0, _typeof3.default)(_rules)) === 'object';
}
(0, _request2.default)(opts, function (err, resp, body) {
if (err) {
reject(err);
return;
}
if (resp.statusCode >= 300) {
reject(new ResponseError(opts, resp, body));
return;
}
resolve(body);
});
});
}
}, {
key: 'get',
value: function get(path, qs) {
var url = this.url;
if (path) url += '/' + path;
return this.process(url, 'GET', qs);
}
}, {
key: 'set',
value: function set(path, payload, qs) {
var url = this.url;
if (path) url += '/' + path;
return this.process(url, 'PUT', qs, payload);
}
}, {
key: 'update',
value: function update(path, payload, qs) {
var url = this.url;
if (path) url += '/' + path;
if (url.endsWith('/.json')) {
// no-op
} else if (url.endsWith('.json')) {
url = url.slice(0, -5) + '/.json';
} else if (url.endsWith('/')) {
url = url + '.json';
} else {
url = url + '/.json';
}
return this.process(url, 'PATCH', qs, payload);
}
}, {
key: 'push',
value: function push(path, patch, qs) {
var url = this.url;
if (path) url += '/' + path;
return this.process(url, 'POST', qs, patch);
}
}, {
key: 'remove',
value: function remove(path, qs) {
var url = this.url;
if (path) url += '/' + path;
return this.process(url, 'DELETE', qs);
}
}], [{
key: 'fixUrl',
value: function fixUrl(url) {
return url.endsWith('.json') ? url : url + '.json';
}
}]);
return Request;
}();
function trimPath(path) {
return path.replace(/\/+$/, '');
}
/**
* Create a firebase rest client factory.
*
* The clients will be bound to a firebase ID. You then can use relative path
* to create references to entities in your Firebase DB.
*
* Usage:
*
* const restFirebase = require('rest-firebase');
* const firebase = restFirebase.factory('some-id');
* const ref = firebase({paths: 'some/path', auth: 'some-oauth-token'});
*
* // you can pass parameters
* // (see https://www.firebase.com/docs/rest/api/#section-query-parameters)
* ref.get({shallow: true}).then(value => {
* // ...
* });
*
* @param {string} target Firebase ID or URL
* @return {function}
*
*/
function restFirebaseFactory(target) {
var rootPath = void 0;
if (VALID_URL.test(target)) {
rootPath = trimPath(target);
} else if (VALID_ID.test(target)) {
rootPath = 'https://' + target + '.firebaseio.com';
} else {
throw new Error(ERR_INVALID_ID);
}
function restFirebase(opts) {
var relPaths = opts && opts.paths || '';
var url = [rootPath].concat(relPaths).join('/');
return new Request((0, _assign2.default)({}, opts, { rootPath: rootPath, url: url }));
}
return restFirebase;
}
exports.Request = Request;
exports.factory = restFirebaseFactory;
特别是 this
未定义的代码部分,抛出错误的是第 3 行:
key: 'get',
value: function get(path, qs) {
var url = this.url;
if (path) url += '/' + path;
return this.process(url, 'GET', qs);
}
通常假设在这种情况下该方法被调用为回调是安全的,这可以通过使用箭头函数或 bind
来解决。如果对象方法未绑定,则不能从对象中分离出来。
考虑到
const dbcmd = FirebaseDb.ref[FirebaseDb.fbcrest[command]]
是名胜,应该是
const dbcmd = FirebaseDb.ref[FirebaseDb.fbcrest[command]].bind(FirebaseDb.ref)
或
const dbcmd = (...args) => FirebaseDb.ref[FirebaseDb.fbcrest[command]](...args)