mirror of
https://github.com/zhigang1992/react-native.git
synced 2026-04-24 04:16:00 +08:00
[Bridge] Add support for JS async functions to RCT_EXPORT_METHOD
Summary:
Adds support for JS async methods and helps guide people writing native modules w.r.t. the callbacks. With this diff, on the native side you write:
```objc
RCT_EXPORT_METHOD(getValueAsync:(NSString *)key
resolver:(RCTPromiseResolver)resolve
rejecter:(RCTPromiseRejecter)reject)
{
NSError *error = nil;
id value = [_nativeDataStore valueForKey:key error:&error];
// "resolve" and "reject" are automatically defined blocks that take
// any object (nil is OK) and an NSError, respectively
if (!error) {
resolve(value);
} else {
reject(error);
}
}
```
On the JS side, you can write:
```js
var {DemoDataStore} = require('react-native').NativeModules;
DemoDataStore.getValueAsync('sample-key').then((value) => {
console.log('Got:', value);
}, (error) => {
console.error(error);
// "error" is an Error object whose message is the NSError's description.
// The NSError's code and domain are also set, and the native trace i
Closes https://github.com/facebook/react-native/pull/1232
Github Author: James Ide <ide@jameside.com>
Test Plan: Imported from GitHub, without a `Test Plan:` line.
This commit is contained in:
@@ -19,9 +19,17 @@ var slice = Array.prototype.slice;
|
||||
|
||||
var MethodTypes = keyMirror({
|
||||
remote: null,
|
||||
remoteAsync: null,
|
||||
local: null,
|
||||
});
|
||||
|
||||
type ErrorData = {
|
||||
message: string;
|
||||
domain: string;
|
||||
code: number;
|
||||
nativeStackIOS?: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates remotely invokable modules.
|
||||
*/
|
||||
@@ -36,21 +44,40 @@ var BatchedBridgeFactory = {
|
||||
*/
|
||||
_createBridgedModule: function(messageQueue, moduleConfig, moduleName) {
|
||||
var remoteModule = mapObject(moduleConfig.methods, function(methodConfig, memberName) {
|
||||
return methodConfig.type === MethodTypes.local ? null : function() {
|
||||
var lastArg = arguments.length > 0 ? arguments[arguments.length - 1] : null;
|
||||
var secondLastArg = arguments.length > 1 ? arguments[arguments.length - 2] : null;
|
||||
var hasSuccCB = typeof lastArg === 'function';
|
||||
var hasErrorCB = typeof secondLastArg === 'function';
|
||||
hasErrorCB && invariant(
|
||||
hasSuccCB,
|
||||
'Cannot have a non-function arg after a function arg.'
|
||||
);
|
||||
var numCBs = (hasSuccCB ? 1 : 0) + (hasErrorCB ? 1 : 0);
|
||||
var args = slice.call(arguments, 0, arguments.length - numCBs);
|
||||
var onSucc = hasSuccCB ? lastArg : null;
|
||||
var onFail = hasErrorCB ? secondLastArg : null;
|
||||
return messageQueue.call(moduleName, memberName, args, onFail, onSucc);
|
||||
};
|
||||
switch (methodConfig.type) {
|
||||
case MethodTypes.remote:
|
||||
return function() {
|
||||
var lastArg = arguments.length > 0 ? arguments[arguments.length - 1] : null;
|
||||
var secondLastArg = arguments.length > 1 ? arguments[arguments.length - 2] : null;
|
||||
var hasErrorCB = typeof lastArg === 'function';
|
||||
var hasSuccCB = typeof secondLastArg === 'function';
|
||||
hasSuccCB && invariant(
|
||||
hasErrorCB,
|
||||
'Cannot have a non-function arg after a function arg.'
|
||||
);
|
||||
var numCBs = (hasSuccCB ? 1 : 0) + (hasErrorCB ? 1 : 0);
|
||||
var args = slice.call(arguments, 0, arguments.length - numCBs);
|
||||
var onSucc = hasSuccCB ? secondLastArg : null;
|
||||
var onFail = hasErrorCB ? lastArg : null;
|
||||
messageQueue.call(moduleName, memberName, args, onSucc, onFail);
|
||||
};
|
||||
|
||||
case MethodTypes.remoteAsync:
|
||||
return function(...args) {
|
||||
return new Promise((resolve, reject) => {
|
||||
messageQueue.call(moduleName, memberName, args, resolve, (errorData) => {
|
||||
var error = _createErrorFromErrorData(errorData);
|
||||
reject(error);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
case MethodTypes.local:
|
||||
return null;
|
||||
|
||||
default:
|
||||
throw new Error('Unknown bridge method type: ' + methodConfig.type);
|
||||
}
|
||||
});
|
||||
for (var constName in moduleConfig.constants) {
|
||||
warning(!remoteModule[constName], 'saw constant and method named %s', constName);
|
||||
@@ -59,7 +86,6 @@ var BatchedBridgeFactory = {
|
||||
return remoteModule;
|
||||
},
|
||||
|
||||
|
||||
create: function(MessageQueue, modulesConfig, localModulesConfig) {
|
||||
var messageQueue = new MessageQueue(modulesConfig, localModulesConfig);
|
||||
return {
|
||||
@@ -80,4 +106,14 @@ var BatchedBridgeFactory = {
|
||||
}
|
||||
};
|
||||
|
||||
function _createErrorFromErrorData(errorData: ErrorData): Error {
|
||||
var {
|
||||
message,
|
||||
...extraErrorInfo,
|
||||
} = errorData;
|
||||
var error = new Error(message);
|
||||
error.framesToPop = 1;
|
||||
return Object.assign(error, extraErrorInfo);
|
||||
}
|
||||
|
||||
module.exports = BatchedBridgeFactory;
|
||||
|
||||
Reference in New Issue
Block a user